1 /*
2  * Copyright (C) 2000 Akira Tagoh <tagoh@src.gnome.org>
3  * Copyright (C) 2000 Reinhard Müller <reinhard@src.gnome.org>
4  * Copyright (C) 2000 - 2005 Rodrigo Moya <rodrigo@gnome-db.org>
5  * Copyright (C) 2001 - 2013 Vivien Malerba <malerba@gnome-db.org>
6  * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
7  * Copyright (C) 2002 Zbigniew Chyla <cyba@gnome.pl>
8  * Copyright (C) 2003 Akira TAGOH <tagoh@gnome-db.org>
9  * Copyright (C) 2003 - 2004 Laurent Sansonetti <lrz@gnome.org>
10  * Copyright (C) 2003 - 2010 Murray Cumming <murrayc@murrayc.com>
11  * Copyright (C) 2004 Alan Knowles <alank@src.gnome.org>
12  * Copyright (C) 2004 Dani Baeyens <daniel.baeyens@hispalinux.es>
13  * Copyright (C) 2005 Stanislav Brabec <sbrabec@suse.de>
14  * Copyright (C) 2008 Przemysław Grzegorczyk <pgrzegorczyk@gmail.com>
15  * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
16  * Copyright (C) 2010 David King <davidk@openismus.com>
17  * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
18  *
19  * This library is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU Lesser General Public
21  * License as published by the Free Software Foundation; either
22  * version 2 of the License, or (at your option) any later version.
23  *
24  * This library is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27  * Lesser General Public License for more details.
28  *
29  * You should have received a copy of the GNU Lesser General Public
30  * License along with this library; if not, write to the
31  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
32  * Boston, MA  02110-1301, USA.
33  */
34 
35 #include <unistd.h>
36 #include <stdio.h>
37 #include <gmodule.h>
38 #include <libgda/gda-config.h>
39 #include <glib/gi18n-lib.h>
40 #include <glib/gstdio.h>
41 #include "gda-marshal.h"
42 #include <string.h>
43 #include <libgda/binreloc/gda-binreloc.h>
44 #include <libgda/gda-data-model-array.h>
45 #include <libgda/gda-data-model-dsn-list.h>
46 #include <libgda/gda-set.h>
47 #include <libgda/gda-holder.h>
48 #include <libgda/gda-log.h>
49 #include <libgda/gda-util.h>
50 #include <libgda/sqlite/gda-sqlite-provider.h>
51 
52 #ifdef HAVE_GIO
53   #include <gio/gio.h>
54 #else
55 #endif
56 #ifdef G_OS_WIN32
57 #include <io.h>
58 #endif
59 
60 #ifdef HAVE_LIBSECRET
61   #include <libsecret/secret.h>
62 #else
63   #ifdef HAVE_GNOME_KEYRING
64   #include <gnome-keyring.h>
65   #endif
66 #endif
67 
68 /*
69    Register GdaDsnInfo type
70 */
71 GType
72 gda_dsn_info_get_type (void)
73 {
74 	static GType type = 0;
75 
76 	if (G_UNLIKELY (type == 0)) {
77         if (type == 0)
78 			type = g_boxed_type_register_static ("GdaDsnInfo",
79 							     (GBoxedCopyFunc) gda_dsn_info_copy,
80 							     (GBoxedFreeFunc) gda_dsn_info_free);
81 	}
82 
83 	return type;
84 }
85 
86 /**
87  * gda_dsn_info_new:
88  *
89  * Creates a new #GdaDsnInfo struct.
90  *
91  * Returns: (transfer full): a new #GdaDsnInfo struct.
92  *
93  * Since: 5.2
94  */
95 GdaDsnInfo*
96 gda_dsn_info_new (void)
97 {
98 	GdaDsnInfo *dsn = g_new0 (GdaDsnInfo, 1);
99 	dsn->name = NULL;
100 	dsn->provider = NULL;
101 	dsn->description = NULL;
102 	dsn->cnc_string = NULL;
103 	dsn->auth_string = NULL;
104 	dsn->is_system = FALSE;
105 	return dsn;
106 }
107 
108 /**
109  * gda_dsn_info_copy:
110  * @source: a #GdaDsnInfo to copy from
111  *
112  * Copy constructor.
113  *
114  * Returns: (transfer full): a new #GdaDsnInfo
115  *
116  * Since: 5.2
117  */
118 GdaDsnInfo *
119 gda_dsn_info_copy (GdaDsnInfo *source)
120 {
121 	GdaDsnInfo *n;
122 	g_return_val_if_fail (source, NULL);
123 	n = gda_dsn_info_new ();
124 	n->name = source->name;
125 	n->provider = source->provider;
126 	n->description = source->description;
127 	n->cnc_string = source->cnc_string;
128 	n->auth_string = source->auth_string;
129 	n->is_system = source->is_system;;
130 	return n;
131 }
132 
133 /**
134  * gda_dsn_info_free:
135  * @dsn: (allow-none): a #GdaDsnInfo struct to free
136  *
137  * Frees any resources taken by @dsn struct. If @dsn is %NULL, then nothing happens.
138  *
139  * Since: 5.2
140  */
141 void
142 gda_dsn_info_free (GdaDsnInfo *dsn)
143 {
144 	g_return_if_fail(dsn);
145 	g_free (dsn);
146 }
147 
148 
149 typedef struct {
150 	GdaProviderInfo    pinfo;
151 	GModule           *handle;
152 	GdaServerProvider *instance;
153 } InternalProvider;
154 
155 struct _GdaConfigPrivate {
156 	gchar *user_file;
157 	gchar *system_file;
158 	gboolean system_config_allowed;
159 	GSList *dsn_list; /* list of GdaDsnInfo structures */
160 	GSList *prov_list; /* list of InternalProvider structures */
161 	gboolean providers_loaded; /* TRUE if providers list has already been scanned */
162 
163 	gboolean emit_signals;
164 };
165 
166 static void gda_config_class_init (GdaConfigClass *klass);
167 static GObject *gda_config_constructor (GType type,
168 					guint n_construct_properties,
169 					GObjectConstructParam *construct_properties);
170 static void gda_config_init       (GdaConfig *conf, GdaConfigClass *klass);
171 static void gda_config_dispose    (GObject *object);
172 static void gda_config_set_property (GObject *object,
173 				     guint param_id,
174 				     const GValue *value,
175 				     GParamSpec *pspec);
176 static void gda_config_get_property (GObject *object,
177 				     guint param_id,
178 				     GValue *value,
179 				     GParamSpec *pspec);
180 static GdaConfig *unique_instance = NULL;
181 #ifdef HAVE_LIBSECRET
182 static gboolean sync_keyring = FALSE;
183 #else
184   #ifdef HAVE_GNOME_KEYRING
185 static gboolean sync_keyring = FALSE;
186   #endif
187 #endif
188 
189 static gint data_source_info_compare (GdaDsnInfo *infoa, GdaDsnInfo *infob);
190 static void data_source_info_free (GdaDsnInfo *info);
191 static void internal_provider_free (InternalProvider *ip);
192 static void load_config_file (const gchar *file, gboolean is_system);
193 static void save_config_file (gboolean is_system);
194 static void load_all_providers (void);
195 static void reload_dsn_configuration (void);
196 
197 
198 enum {
199 	DSN_ADDED,
200 	DSN_TO_BE_REMOVED,
201 	DSN_REMOVED,
202 	DSN_CHANGED,
203 	LAST_SIGNAL
204 };
205 
206 static gint gda_config_signals[LAST_SIGNAL] = { 0, 0, 0, 0 };
207 
208 /* properties */
209 enum {
210 	PROP_0,
211 	PROP_USER_FILE,
212 	PROP_SYSTEM_FILE
213 };
214 
215 static GObjectClass *parent_class = NULL;
216 
217 #ifdef HAVE_GIO
218 /*
219  * GIO static variables
220  */
221 static GFileMonitor *mon_conf_user = NULL;
222 static GFileMonitor *mon_conf_global = NULL;
223 gulong user_notify_changes = 0;
224 gulong global_notify_changes = 0;
225 
226 static void conf_file_changed (GFileMonitor *mon, GFile *file, GFile *other_file,
227 			       GFileMonitorEvent event_type, gpointer data);
228 static void lock_notify_changes (void);
229 static void unlock_notify_changes (void);
230 #endif
231 
232 static GRecMutex gda_rmutex;
233 #define GDA_CONFIG_LOCK() g_rec_mutex_lock(&gda_rmutex)
234 #define GDA_CONFIG_UNLOCK() g_rec_mutex_unlock(&gda_rmutex)
235 
236 /* GdaServerProvider for SQLite as a shortcut, available
237  * even if the SQLite provider is not installed
238  */
239 GdaServerProvider *_gda_config_sqlite_provider = NULL;
240 
241 /*
242  * GdaConfig class implementation
243  * @klass:
244  */
245 static void
246 gda_config_class_init (GdaConfigClass *klass)
247 {
248 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
249 
250 	parent_class = g_type_class_peek_parent (klass);
251 
252 	/**
253 	 * GdaConfig::dsn-added:
254 	 * @conf: the #GdaConfig object
255 	 * @new_dsn: a #GdaDsnInfo
256 	 *
257 	 * Gets emitted whenever a new DSN has been defined
258 	 */
259 	gda_config_signals[DSN_ADDED] =
260                 g_signal_new ("dsn-added",
261                               G_TYPE_FROM_CLASS (object_class),
262                               G_SIGNAL_RUN_FIRST,
263                               G_STRUCT_OFFSET (GdaConfigClass, dsn_added),
264                               NULL, NULL,
265                               _gda_marshal_VOID__POINTER,
266                               G_TYPE_NONE, 1, G_TYPE_POINTER);
267 	/**
268 	 * GdaConfig::dsn-to-be-removed:
269 	 * @conf: the #GdaConfig object
270 	 * @old_dsn: a #GdaDsnInfo
271 	 *
272 	 * Gets emitted whenever a DSN is about to be removed
273 	 */
274 	gda_config_signals[DSN_TO_BE_REMOVED] =
275                 g_signal_new ("dsn-to-be-removed",
276                               G_TYPE_FROM_CLASS (object_class),
277                               G_SIGNAL_RUN_FIRST,
278                               G_STRUCT_OFFSET (GdaConfigClass, dsn_to_be_removed),
279                               NULL, NULL,
280                               _gda_marshal_VOID__POINTER,
281                               G_TYPE_NONE, 1, G_TYPE_POINTER);
282 	/**
283 	 * GdaConfig::dsn-removed:
284 	 * @conf: the #GdaConfig object
285 	 * @old_dsn: a #GdaDsnInfo
286 	 *
287 	 * Gets emitted whenever a DSN has been removed
288 	 */
289 	gda_config_signals[DSN_REMOVED] =
290                 g_signal_new ("dsn-removed",
291                               G_TYPE_FROM_CLASS (object_class),
292                               G_SIGNAL_RUN_FIRST,
293                               G_STRUCT_OFFSET (GdaConfigClass, dsn_removed),
294                               NULL, NULL,
295                               _gda_marshal_VOID__POINTER,
296                               G_TYPE_NONE, 1, G_TYPE_POINTER);
297 	/**
298 	 * GdaConfig::dsn-changed:
299 	 * @conf: the #GdaConfig object
300 	 * @dsn: a #GdaDsnInfo
301 	 *
302 	 * Gets emitted whenever a DSN's definition has been changed
303 	 */
304 	gda_config_signals[DSN_CHANGED] =
305                 g_signal_new ("dsn-changed",
306                               G_TYPE_FROM_CLASS (object_class),
307                               G_SIGNAL_RUN_FIRST,
308                               G_STRUCT_OFFSET (GdaConfigClass, dsn_changed),
309                               NULL, NULL,
310                               _gda_marshal_VOID__POINTER,
311                               G_TYPE_NONE, 1, G_TYPE_POINTER);
312 
313 	/* Properties */
314         object_class->set_property = gda_config_set_property;
315         object_class->get_property = gda_config_get_property;
316 
317 	/**
318 	 * GdaConfig:user-filename:
319 	 *
320 	 * File to use for per-user DSN list. When changed, the whole list of DSN will be reloaded.
321 	 */
322 	/* To translators: DSN stands for Data Source Name, it's a named connection string defined in $XDG_DATA_HOME/libgda/config */
323 	g_object_class_install_property (object_class, PROP_USER_FILE,
324                                          g_param_spec_string ("user-filename", NULL,
325 							      "File to use for per-user DSN list",
326 							      NULL,
327 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
328 	/**
329 	 * GdaConfig:system-filename:
330 	 *
331 	 * File to use for system-wide DSN list. When changed, the whole list of DSN will be reloaded.
332 	 */
333 	/* To translators: DSN stands for Data Source Name, it's a named connection string defined in $PREFIX/etc/libgda-5.0/config */
334 	g_object_class_install_property (object_class, PROP_SYSTEM_FILE,
335                                          g_param_spec_string ("system-filename", NULL,
336 							      "File to use for system-wide DSN list",
337 							      NULL,
338 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
339 
340 	object_class->constructor = gda_config_constructor;
341 	object_class->dispose = gda_config_dispose;
342 }
343 
344 static void
345 gda_config_init (GdaConfig *conf, G_GNUC_UNUSED GdaConfigClass *klass)
346 {
347 	g_return_if_fail (GDA_IS_CONFIG (conf));
348 
349 	conf->priv = g_new0 (GdaConfigPrivate, 1);
350 	conf->priv->user_file = NULL;
351 	conf->priv->system_file = NULL;
352 	conf->priv->system_config_allowed = FALSE;
353 	conf->priv->prov_list = NULL;
354 	conf->priv->dsn_list = NULL;
355 	conf->priv->providers_loaded = FALSE;
356 	conf->priv->emit_signals = TRUE;
357 }
358 
359 #ifdef HAVE_LIBSECRET
360 static void
361 secret_password_found_cb (GObject *source_object, GAsyncResult *res, gchar *dsnname)
362 {
363 	gchar *auth;
364 	GError *error = NULL;
365 	auth = secret_password_lookup_finish (res, &error);
366         if (auth) {
367 		GdaDsnInfo *dsn;
368 		dsn = gda_config_get_dsn_info (dsnname);
369 		if (dsn) {
370 			if (dsn->auth_string && auth && !strcmp (dsn->auth_string, auth))
371 				return;
372 
373 			g_free (dsn->auth_string);
374 			dsn->auth_string = g_strdup (auth);
375 		}
376 		/*g_print ("Loaded auth info for '%s'\n", dsnname);*/
377 		if (unique_instance->priv->emit_signals)
378 			g_signal_emit (unique_instance, gda_config_signals [DSN_CHANGED], 0, dsn);
379 		g_free (auth);
380 	}
381 	else if (error) {
382 		gda_log_message (_("Error loading authentication information for '%s' DSN: %s"),
383 				 dsnname, error->message ? error->message : _("No detail"));
384 		g_clear_error (&error);
385 	}
386 	g_free (dsnname);
387 }
388 #else
389   #ifdef HAVE_GNOME_KEYRING
390 static void
391 password_found_cb (GnomeKeyringResult res, const gchar *password, const gchar *dsnname)
392 {
393         if (res == GNOME_KEYRING_RESULT_OK) {
394 		GdaDsnInfo *dsn;
395 		dsn = gda_config_get_dsn_info (dsnname);
396 		if (dsn) {
397 			if (dsn->auth_string && password && !strcmp (dsn->auth_string, password))
398 				return;
399 
400 			g_free (dsn->auth_string);
401 			dsn->auth_string = g_strdup (password);
402 		}
403 		/*g_print ("Loaded auth info for '%s'\n", dsnname);*/
404 		if (unique_instance->priv->emit_signals)
405 			g_signal_emit (unique_instance, gda_config_signals [DSN_CHANGED], 0, dsn);
406 	}
407 	else if (res != GNOME_KEYRING_RESULT_NO_MATCH)
408 		gda_log_message (_("Error loading authentication information for '%s' DSN: %s"),
409 				 dsnname, gnome_keyring_result_to_message (res));
410 }
411   #endif
412 #endif
413 
414 static void
415 load_config_file (const gchar *file, gboolean is_system)
416 {
417 	xmlDocPtr doc;
418 	xmlNodePtr root;
419 
420 	if (!g_file_test (file, G_FILE_TEST_EXISTS))
421 		return;
422 
423 	doc = xmlParseFile (file);
424 	if (!doc)
425 		return;
426 
427 	root = xmlDocGetRootElement (doc);
428 	if (root) {
429 		xmlNodePtr node;
430 		for (node = root->children; node; node = node->next) { /* iter over the <section> tags */
431 			if (strcmp ((gchar *) node->name, "section"))
432 				continue;
433 
434 			xmlChar *prop;
435 			gchar *ptr;
436 			GdaDsnInfo *info;
437 			gboolean is_new = FALSE;
438 			xmlNodePtr entry;
439 
440 			prop = xmlGetProp (node, BAD_CAST "path");
441 			if (!prop)
442 				continue;
443 			for (ptr = ((gchar *) prop) + strlen ((gchar *) prop) - 1; ptr >= (gchar *) prop; ptr--) {
444 				if (*ptr == '/') {
445 					ptr++;
446 					break;
447 				}
448 			}
449 			info = gda_config_get_dsn_info (ptr);
450 			if (!info) {
451 				info = g_new0 (GdaDsnInfo, 1);
452 				info->name = g_strdup (ptr);
453 				is_new = TRUE;
454 			}
455 			else {
456 				g_free (info->provider); info->provider = NULL;
457 				g_free (info->cnc_string); info->cnc_string = NULL;
458 				g_free (info->description); info->description = NULL;
459 				g_free (info->auth_string); info->auth_string = NULL;
460 			}
461 			info->is_system = is_system;
462 			xmlFree (prop);
463 
464 			gchar *username = NULL, *password = NULL;
465 			for (entry = node->children; entry; entry = entry->next) { /* iter over the <entry> tags */
466 				xmlChar *value;
467 				if (strcmp ((gchar *)entry->name, "entry"))
468 					continue;
469 				prop = xmlGetProp (entry, BAD_CAST "name");
470 				if (!prop)
471 					continue;
472 				value = xmlGetProp (entry, BAD_CAST "value");
473 				if (!value) {
474 					xmlFree (prop);
475 					continue;
476 				}
477 				if (!strcmp ((gchar *) prop, "DSN"))
478 					info->cnc_string = g_strdup ((gchar *)value);
479 				else if (!strcmp ((gchar *) prop, "Provider")) {
480 					GdaProviderInfo *pinfo;
481 					pinfo = gda_config_get_provider_info ((gchar *)value);
482 					if (pinfo)
483 						info->provider = g_strdup (pinfo->id);
484 					else
485 						info->provider = g_strdup ((gchar *)value);
486 				}
487 				else if (!strcmp ((gchar *) prop, "Description"))
488 					info->description = g_strdup ((gchar *)value);
489 				if (!strcmp ((gchar *) prop, "Auth"))
490 					info->auth_string = g_strdup ((gchar *)value);
491 				else if (!strcmp ((gchar *) prop, "Username"))
492 					username = g_strdup ((gchar*) value);
493 				else if (!strcmp ((gchar *) prop, "Password"))
494 					password =  g_strdup ((gchar*) value);
495 				xmlFree (prop);
496 				xmlFree (value);
497 			}
498 
499 			if (username && *username) {
500 				if (!info->auth_string) {
501 					/* migrate username/password to auth_string */
502 					gchar *s1;
503 					s1 = gda_rfc1738_encode (username);
504 					if (password) {
505 						gchar *s2;
506 						s2 = gda_rfc1738_encode (password);
507 						info->auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
508 						g_free (s2);
509 					}
510 					else
511 						info->auth_string = g_strdup_printf ("USERNAME=%s", s1);
512 					g_free (s1);
513 				}
514 			}
515 			g_free (username);
516 			g_free (password);
517 
518 #ifdef HAVE_LIBSECRET
519 			if (! is_system) {
520 				if (sync_keyring) {
521 					GError *error = NULL;
522 					gchar *auth = NULL;
523 					auth = secret_password_lookup_sync (SECRET_SCHEMA_COMPAT_NETWORK,
524 									    NULL, &error,
525 									    "server", info->name, NULL);
526 					if (auth) {
527 						/*g_print ("Loaded sync. auth info for '%s': %s\n", info->name, auth);*/
528 						info->auth_string = g_strdup (auth);
529 						g_free (auth);
530 					}
531 					else if (error) {
532 						gda_log_message (_("Error loading authentication information for '%s' DSN: %s"),
533 								 info->name, error->message ? error->message : _("No detail"));
534 						g_clear_error (&error);
535 					}
536 				}
537 				else {
538 					secret_password_lookup (SECRET_SCHEMA_COMPAT_NETWORK,
539 								NULL, (GAsyncReadyCallback) secret_password_found_cb,
540 								g_strdup (info->name),
541 								"server", info->name, NULL);
542 				}
543 			}
544 #else
545   #ifdef HAVE_GNOME_KEYRING
546 			if (! is_system) {
547 				if (sync_keyring) {
548 					GnomeKeyringResult res;
549 					gchar *auth = NULL;
550 					res = gnome_keyring_find_password_sync (GNOME_KEYRING_NETWORK_PASSWORD, &auth,
551 										"server", info->name, NULL);
552 					if (res == GNOME_KEYRING_RESULT_OK) {
553 						/*g_print ("Loaded sync. auth info for '%s': %s\n", info->name, auth);*/
554 						info->auth_string = g_strdup (auth);
555 					}
556 					else if (res != GNOME_KEYRING_RESULT_NO_MATCH)
557 						gda_log_message (_("Error loading authentication information for '%s' DSN: %s"),
558 								 info->name, gnome_keyring_result_to_message (res));
559 					if (auth)
560 						gnome_keyring_free_password (auth);
561 				}
562 				else {
563 					gchar *tmp = g_strdup (info->name);
564 					gnome_keyring_find_password (GNOME_KEYRING_NETWORK_PASSWORD,
565 								     (GnomeKeyringOperationGetStringCallback) password_found_cb,
566 								     tmp, g_free,
567 								     "server", tmp, NULL);
568 				}
569 			}
570   #endif
571 #endif
572 			/* signals */
573 			if (is_new) {
574 				unique_instance->priv->dsn_list = g_slist_insert_sorted (unique_instance->priv->dsn_list, info,
575 											 (GCompareFunc) data_source_info_compare);
576 				if (unique_instance->priv->emit_signals)
577 					g_signal_emit (unique_instance, gda_config_signals[DSN_ADDED], 0, info);
578 			}
579 			else if (unique_instance->priv->emit_signals)
580 				g_signal_emit (unique_instance, gda_config_signals[DSN_CHANGED], 0, info);
581 		}
582 	}
583 	xmlFreeDoc (doc);
584 }
585 
586 static void
587 save_config_file (gboolean is_system)
588 {
589 	xmlDocPtr doc;
590 	xmlNodePtr root;
591 	GSList *list;
592 
593 	if (!unique_instance)
594 		gda_config_get ();
595 
596 	if ((!is_system && !unique_instance->priv->user_file) ||
597 	    (is_system && !unique_instance->priv->system_file)) {
598 		return;
599 	}
600 
601 	doc = xmlNewDoc (BAD_CAST "1.0");
602 	root = xmlNewDocNode (doc, NULL, BAD_CAST "libgda-config", NULL);
603         xmlDocSetRootElement (doc, root);
604 	for (list = unique_instance->priv->dsn_list; list; list = list->next) {
605 		GdaDsnInfo *info = (GdaDsnInfo*) list->data;
606 		if (info->is_system != is_system)
607 			continue;
608 
609 		xmlNodePtr section, entry;
610 		gchar *prop;
611 		section = xmlNewChild (root, NULL, BAD_CAST "section", NULL);
612 		prop = g_strdup_printf ("/apps/libgda/Datasources/%s", info->name);
613 		xmlSetProp (section, BAD_CAST "path", BAD_CAST prop);
614 		g_free (prop);
615 
616 		/* provider */
617 		entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL);
618 		xmlSetProp (entry, BAD_CAST "name", BAD_CAST "Provider");
619 		xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string");
620 		xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->provider));
621 
622 		/* DSN */
623 		entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL);
624 		xmlSetProp (entry, BAD_CAST "name", BAD_CAST "DSN");
625 		xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string");
626 		xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->cnc_string));
627 
628 #if !defined (HAVE_GNOME_KEYRING) && !defined (HAVE_LIBSECRET)
629 		if (! is_system) {
630 			/* auth */
631 			entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL);
632 			xmlSetProp (entry, BAD_CAST "name", BAD_CAST "Auth");
633 			xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string");
634 			xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->auth_string));
635 		}
636 #endif
637 
638 		/* description */
639 		entry = xmlNewChild (section, NULL, BAD_CAST "entry", NULL);
640 		xmlSetProp (entry, BAD_CAST "name", BAD_CAST "Description");
641 		xmlSetProp (entry, BAD_CAST "type", BAD_CAST "string");
642 		xmlSetProp (entry, BAD_CAST "value", BAD_CAST (info->description));
643 	}
644 
645 #ifdef HAVE_GIO
646 	lock_notify_changes ();
647 #endif
648 	if (!is_system && unique_instance->priv->user_file) {
649 		if (xmlSaveFormatFile (unique_instance->priv->user_file, doc, TRUE) == -1)
650                         gda_log_error ("Error saving config data to '%s'", unique_instance->priv->user_file);
651 	}
652 	else if (is_system && unique_instance->priv->system_file) {
653 		if (xmlSaveFormatFile (unique_instance->priv->system_file, doc, TRUE) == -1)
654                         gda_log_error ("Error saving config data to '%s'", unique_instance->priv->system_file);
655 	}
656 	fflush (NULL);
657 #ifdef HAVE_GIO
658 	unlock_notify_changes ();
659 #endif
660 	xmlFreeDoc (doc);
661 }
662 
663 static GObject *
664 gda_config_constructor (GType type,
665 			guint n_construct_properties,
666 			GObjectConstructParam *construct_properties)
667 {
668 	GObject *object;
669 
670 	if (!unique_instance) {
671 #if defined(HAVE_LIBSECRET) || defined(HAVE_GNOME_KEYRING)
672 		if (g_getenv ("GDA_CONFIG_SYNCHRONOUS"))
673 			sync_keyring = TRUE;
674 #endif
675 
676 		guint i;
677 		gboolean user_file_set = FALSE, system_file_set = FALSE;
678 
679 		object = G_OBJECT_CLASS (parent_class)->constructor (type,
680 								     n_construct_properties,
681 								     construct_properties);
682 		for (i = 0; i< n_construct_properties; i++) {
683 			GObjectConstructParam *prop = &(construct_properties[i]);
684 			if (!strcmp (g_param_spec_get_name (prop->pspec), "user-filename")) {
685 				user_file_set = TRUE;
686 				/*g_print ("GdaConfig user dir set\n");*/
687 			}
688 			else if (!strcmp (g_param_spec_get_name (prop->pspec), "system-filename")) {
689 				system_file_set = TRUE;
690 				/*g_print ("GdaConfig system dir set\n");*/
691 			}
692 		}
693 
694 		unique_instance = GDA_CONFIG (object);
695 		g_object_ref (object); /* keep one reference for the library */
696 
697 		/* define user and system dirs. if not already defined */
698 		if (!user_file_set) {
699 			gchar *confdir, *conffile;
700 			gboolean setup_ok = TRUE;
701 			confdir = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), "libgda", NULL);
702 			conffile = g_build_filename (confdir, "config", NULL);
703 
704 			if (!g_file_test (confdir, G_FILE_TEST_EXISTS)) {
705 				gchar *old_path;
706 				old_path = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), ".libgda", NULL); /* Flawfinder: ignore */
707 				if (g_file_test (old_path, G_FILE_TEST_EXISTS)) {
708 					/* using $HOME/.libgda because it exists */
709 					g_free (confdir);
710 					confdir = old_path;
711 					g_free (conffile);
712 					conffile = g_build_filename (confdir, "config", NULL);
713 				}
714 				else {
715 					g_free (old_path);
716 					if (g_mkdir_with_parents (confdir, 0700)) {
717 						setup_ok = FALSE;
718 						gda_log_error (_("Error creating user specific "
719 								 "configuration directory '%s'"),
720 							       confdir);
721 					}
722 					if (setup_ok) {
723 						gchar *str;
724 						gchar *full_file;
725 						gsize len;
726 #define DB_FILE "sales_test.db"
727 #define DEFAULT_CONFIG \
728 "<?xml version=\"1.0\"?>\n" \
729 "<libgda-config>\n" \
730 "    <section path=\"/apps/libgda/Datasources/SalesTest\">\n" \
731 "        <entry name=\"DSN\" type=\"string\" value=\"DB_DIR=%s;DB_NAME=sales_test.db\"/>\n" \
732 "        <entry name=\"Description\" type=\"string\" value=\"Test database for a sales department\"/>\n" \
733 "        <entry name=\"Provider\" type=\"string\" value=\"SQLite\"/>\n" \
734 "    </section>\n" \
735 "</libgda-config>\n"
736 #define DEFAULT_CONFIG_EMPTY \
737 "<?xml version=\"1.0\"?>\n" \
738 "<libgda-config>\n" \
739 "    <!-- User specific data sources go here -->\n" \
740 "</libgda-config>\n"
741 
742 						str = gda_gbr_get_file_path (GDA_ETC_DIR,
743 									     LIBGDA_ABI_NAME, DB_FILE, NULL);
744 						if (g_file_get_contents (str, &full_file, &len, NULL)) {
745 							gchar *dbfile;
746 
747 							/* copy the Sales test database */
748 							dbfile = g_build_filename (confdir, DB_FILE, NULL);
749 							if (g_file_set_contents (dbfile, full_file, len, NULL)) {
750 								gchar *str2;
751 								str2 = g_strdup_printf (DEFAULT_CONFIG, confdir);
752 								g_file_set_contents (conffile, str2, -1, NULL);
753 								g_free (str2);
754 							}
755 							else
756 								g_file_set_contents (conffile, DEFAULT_CONFIG_EMPTY, -1, NULL);
757 							g_free (dbfile);
758 							g_free (full_file);
759 						}
760 						else
761 							g_file_set_contents (conffile, DEFAULT_CONFIG_EMPTY, -1, NULL);
762 						g_free (str);
763 					}
764 				}
765 				if (setup_ok && !g_file_test (confdir, G_FILE_TEST_IS_DIR)) {
766 					setup_ok = FALSE;
767 					gda_log_message (_("User specific "
768 							   "configuration directory '%s' exists and is not a directory"),
769 							 confdir);
770 				}
771 				g_free (confdir);
772 
773 				if (setup_ok)
774 					unique_instance->priv->user_file = conffile;
775 				else
776 					g_free (conffile);
777 			}
778 			else {
779 				if (!g_file_test (confdir, G_FILE_TEST_IS_DIR)) {
780 					gda_log_message (_("User specific "
781 							   "configuration directory '%s' exists and is not a directory"),
782 							 confdir);
783 					g_free (conffile);
784 				}
785 				else
786 					unique_instance->priv->user_file = conffile;
787 				g_free (confdir);
788 			}
789 		}
790 		if (!system_file_set)
791 			unique_instance->priv->system_file = gda_gbr_get_file_path (GDA_ETC_DIR,
792 										    LIBGDA_ABI_NAME, "config", NULL);
793 		unique_instance->priv->system_config_allowed = FALSE;
794 		if (unique_instance->priv->system_file) {
795 #ifdef G_OS_WIN32
796 
797 			FILE *file;
798                         file = fopen (unique_instance->priv->system_file, "a");  /* Flawfinder: ignore */
799                         if (file) {
800                                 unique_instance->priv->system_config_allowed = TRUE;
801                                 fclose (file);
802                         }
803 #else
804 			struct stat stbuf;
805 			if (stat (unique_instance->priv->system_file, &stbuf) == 0) {
806 				/* use effective user and group IDs */
807 				uid_t euid;
808 				gid_t egid;
809 				euid = geteuid ();
810 				egid = getegid ();
811 				if (euid == stbuf.st_uid) {
812 					if ((stbuf.st_mode & S_IWUSR) && (stbuf.st_mode & S_IRUSR))
813 						unique_instance->priv->system_config_allowed = TRUE;
814 				}
815 				else if (egid == stbuf.st_gid) {
816 					if ((stbuf.st_mode & S_IWGRP) && (stbuf.st_mode & S_IRGRP))
817 						unique_instance->priv->system_config_allowed = TRUE;
818 				}
819 				else if ((stbuf.st_mode & S_IWOTH) && (stbuf.st_mode & S_IROTH))
820 					unique_instance->priv->system_config_allowed = TRUE;
821 			}
822 #endif
823 		}
824 
825 		/* Setup file monitoring */
826 #ifdef HAVE_GIO
827 		if (unique_instance->priv->user_file) {
828 			GFile *gf;
829 			gf = g_file_new_for_path (unique_instance->priv->user_file);
830 			mon_conf_user = g_file_monitor_file (gf, G_FILE_MONITOR_NONE, NULL, NULL);
831 			if (mon_conf_user)
832 				g_signal_connect (G_OBJECT (mon_conf_user), "changed",
833 						  G_CALLBACK (conf_file_changed), NULL);
834 			g_object_unref (gf);
835 		}
836 
837 		if (unique_instance->priv->system_file) {
838 			GFile *gf;
839 			gf = g_file_new_for_path (unique_instance->priv->system_file);
840 			mon_conf_global = g_file_monitor_file (gf, G_FILE_MONITOR_NONE, NULL, NULL);
841 			if (mon_conf_user)
842 				g_signal_connect (G_OBJECT (mon_conf_global), "changed",
843 						  G_CALLBACK (conf_file_changed), NULL);
844 			g_object_unref (gf);
845 		}
846 #endif
847 		/* load existing DSN definitions */
848 		if (unique_instance->priv->system_file)
849 			load_config_file (unique_instance->priv->system_file, TRUE);
850 		if (unique_instance->priv->user_file)
851 			load_config_file (unique_instance->priv->user_file, FALSE);
852 	}
853 	else
854 		object = g_object_ref (G_OBJECT (unique_instance));
855 
856 	return object;
857 }
858 
859 static void
860 gda_config_dispose (GObject *object)
861 {
862 	GdaConfig *conf = (GdaConfig *) object;
863 
864 	g_return_if_fail (GDA_IS_CONFIG (conf));
865 
866 	if (conf->priv) {
867 		g_free (conf->priv->user_file);
868 		g_free (conf->priv->system_file);
869 
870 		if (conf->priv->dsn_list) {
871 			g_slist_foreach (conf->priv->dsn_list, (GFunc) data_source_info_free, NULL);
872 			g_slist_free (conf->priv->dsn_list);
873 		}
874 		if (conf->priv->prov_list) {
875 			g_slist_foreach (conf->priv->prov_list, (GFunc) internal_provider_free, NULL);
876 			g_slist_free (conf->priv->prov_list);
877 		}
878 		g_free (conf->priv);
879 		conf->priv = NULL;
880 	}
881 
882 	/* chain to parent class */
883 	parent_class->dispose (object);
884 }
885 
886 
887 /* module error */
888 GQuark gda_config_error_quark (void)
889 {
890         static GQuark quark;
891         if (!quark)
892                 quark = g_quark_from_static_string ("gda_config_error");
893         return quark;
894 }
895 
896 /**
897  * gda_config_get_type:
898  *
899  * Registers the #GdaConfig class on the GLib type system.
900  *
901  * Returns: the GType identifying the class.
902  */
903 GType
904 gda_config_get_type (void)
905 {
906 	static GType type = 0;
907 
908 	if (G_UNLIKELY (type == 0)) {
909 		static GTypeInfo info = {
910 			sizeof (GdaConfigClass),
911 			(GBaseInitFunc) NULL,
912 			(GBaseFinalizeFunc) NULL,
913 			(GClassInitFunc) gda_config_class_init,
914 			NULL, NULL,
915 			sizeof (GdaConfig),
916 			0,
917 			(GInstanceInitFunc) gda_config_init,
918 			0
919 		};
920 		GDA_CONFIG_LOCK ();
921 		if (type == 0)
922 			type = g_type_register_static (G_TYPE_OBJECT, "GdaConfig", &info, 0);
923 		GDA_CONFIG_UNLOCK ();
924 	}
925 
926 	return type;
927 }
928 
929 static void
930 gda_config_set_property (GObject *object,
931 			 guint param_id,
932 			 const GValue *value,
933 			 GParamSpec *pspec)
934 {
935 	GdaConfig *conf;
936 	const gchar *cstr;
937 
938         conf = GDA_CONFIG (object);
939         if (conf->priv) {
940                 switch (param_id) {
941 		case PROP_USER_FILE:
942 			cstr = g_value_get_string (value);
943 			if ((cstr && conf->priv->user_file &&
944 			     !strcmp (cstr, conf->priv->user_file)) ||
945 			    (! cstr && !conf->priv->user_file)) {
946 				/* nothing to do */
947 				break;
948 			}
949 			g_free (conf->priv->user_file);
950 			conf->priv->user_file = NULL;
951 			if (g_value_get_string (value))
952 				conf->priv->user_file = g_strdup (cstr);
953 			reload_dsn_configuration ();
954 			break;
955                 case PROP_SYSTEM_FILE:
956 			cstr = g_value_get_string (value);
957 			if ((cstr && conf->priv->system_file &&
958 			     !strcmp (cstr, conf->priv->system_file)) ||
959 			    (! cstr && !conf->priv->system_file)) {
960 				/* nothing to do */
961 				break;
962 			}
963 			g_free (conf->priv->system_file);
964 			conf->priv->system_file = NULL;
965 			if (g_value_get_string (value))
966 				conf->priv->system_file = g_strdup (cstr);
967 			reload_dsn_configuration ();
968                         break;
969 		default:
970 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
971 			break;
972 		}
973 	}
974 }
975 
976 static void
977 gda_config_get_property (GObject *object,
978 			 guint param_id,
979 			 GValue *value,
980 			 GParamSpec *pspec)
981 {
982 	GdaConfig *conf;
983 
984 	conf = GDA_CONFIG (object);
985 	if (conf->priv) {
986 		switch (param_id) {
987 		case PROP_USER_FILE:
988 			g_value_set_string (value, conf->priv->user_file);
989 			break;
990 		case PROP_SYSTEM_FILE:
991 			g_value_set_string (value, conf->priv->system_file);
992 			break;
993 		default:
994 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
995 			break;
996 		}
997 	}
998 }
999 
1000 /**
1001  * gda_config_get:
1002  *
1003  * Get a pointer to the global (unique) #GdaConfig object. This functions increments
1004  * the reference count of the object, so you need to call g_object_unref() on it once finished.
1005  *
1006  * Returns: (transfer full): a non %NULL pointer to the unique #GdaConfig
1007  */
1008 GdaConfig*
1009 gda_config_get (void)
1010 {
1011 	GDA_CONFIG_LOCK ();
1012 	g_object_new (GDA_TYPE_CONFIG, NULL);
1013 	g_assert (unique_instance);
1014 	GDA_CONFIG_UNLOCK ();
1015 	return unique_instance;
1016 }
1017 
1018 /**
1019  * gda_config_get_dsn_info:
1020  * @dsn_name: the name of the DSN to look for
1021  *
1022  * Get information about the DSN named @dsn_name.
1023  *
1024  * @dsn_name's format is "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;" (if &lt;username&gt;
1025  * and optionally &lt;password&gt; are provided, they are ignored). Also see the gda_dsn_split() utility
1026  * function.
1027  *
1028  * Returns: (transfer none): a pointer to read-only #GdaDsnInfo structure, or %NULL if not found
1029  */
1030 GdaDsnInfo *
1031 gda_config_get_dsn_info (const gchar *dsn_name)
1032 {
1033 	GSList *list;
1034 
1035 	g_return_val_if_fail (dsn_name, NULL);
1036 
1037 	gchar *user, *pass, *real_dsn;
1038         gda_dsn_split (dsn_name, &real_dsn, &user, &pass);
1039 	g_free (user);
1040 	g_free (pass);
1041         if (!real_dsn) {
1042 		gda_log_message (_("Malformed data source name '%s'"), dsn_name);
1043                 return NULL;
1044 	}
1045 
1046 	GDA_CONFIG_LOCK ();
1047 	if (!unique_instance)
1048 		gda_config_get ();
1049 
1050 	for (list = unique_instance->priv->dsn_list; list; list = list->next)
1051 		if (!strcmp (((GdaDsnInfo*) list->data)->name, real_dsn)) {
1052 			GDA_CONFIG_UNLOCK ();
1053 			g_free (real_dsn);
1054 			return (GdaDsnInfo*) list->data;
1055 		}
1056 	GDA_CONFIG_UNLOCK ();
1057 	g_free (real_dsn);
1058 	return NULL;
1059 }
1060 
1061 #ifdef HAVE_LIBSECRET
1062 static void
1063 secret_password_stored_cb (GObject *source_object, GAsyncResult *res, gchar *dsnname)
1064 {
1065 	GError *error = NULL;
1066 	if (! secret_password_store_finish (res, &error)) {
1067 		gda_log_error (_("Couldn't save authentication information for DSN '%s': %s"),
1068 			       dsnname, error && error->message ? error->message : _("No detail"));
1069 		g_clear_error (&error);
1070 	}
1071 	g_free (dsnname);
1072 }
1073 #else
1074   #ifdef HAVE_GNOME_KEYRING
1075 static void
1076 password_stored_cb (GnomeKeyringResult res, const gchar *dsnname)
1077 {
1078         if (res != GNOME_KEYRING_RESULT_OK)
1079                 gda_log_error (_("Couldn't save authentication information for DSN '%s': %s"), dsnname,
1080 			       gnome_keyring_result_to_message (res));
1081 }
1082   #endif
1083 #endif
1084 
1085 /**
1086  * gda_config_define_dsn:
1087  * @info: a pointer to a filled GdaDsnInfo structure
1088  * @error: a place to store errors, or %NULL
1089  *
1090  * Add or update a DSN from the definition in @info.
1091  *
1092  * This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
1093  *
1094  * Returns: TRUE if no error occurred
1095  */
1096 gboolean
1097 gda_config_define_dsn (const GdaDsnInfo *info, GError **error)
1098 {
1099 	GdaDsnInfo *einfo;
1100 	gboolean save_user = FALSE;
1101 	gboolean save_system = FALSE;
1102 
1103 	g_return_val_if_fail (info, FALSE);
1104 	g_return_val_if_fail (info->name, FALSE);
1105 
1106 	GDA_CONFIG_LOCK ();
1107 	if (!unique_instance)
1108 		gda_config_get ();
1109 
1110 	if (info->is_system && !unique_instance->priv->system_config_allowed) {
1111 		g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PERMISSION_ERROR,
1112 			      "%s", _("Can't manage system-wide configuration"));
1113 		GDA_CONFIG_UNLOCK ();
1114 		return FALSE;
1115 	}
1116 
1117 	if (info->is_system)
1118 		save_system = TRUE;
1119 	else
1120 		save_user = TRUE;
1121 	einfo = gda_config_get_dsn_info (info->name);
1122 	if (einfo) {
1123 		g_free (einfo->provider); einfo->provider = NULL;
1124 		g_free (einfo->cnc_string); einfo->cnc_string = NULL;
1125 		g_free (einfo->description); einfo->description = NULL;
1126 		g_free (einfo->auth_string); einfo->auth_string = NULL;
1127 		if (info->provider)
1128 			einfo->provider = g_strdup (info->provider);
1129 		if (info->cnc_string)
1130 			einfo->cnc_string = g_strdup (info->cnc_string);
1131 		if (info->description)
1132 			einfo->description = g_strdup (info->description);
1133 		if (info->auth_string)
1134 			einfo->auth_string = g_strdup (info->auth_string);
1135 
1136 		if (info->is_system != einfo->is_system) {
1137 			save_system = TRUE;
1138 			save_user = TRUE;
1139 			einfo->is_system = info->is_system ? TRUE : FALSE;
1140 		}
1141 		if (unique_instance->priv->emit_signals)
1142 			g_signal_emit (unique_instance, gda_config_signals[DSN_CHANGED], 0, einfo);
1143 	}
1144 	else {
1145 		einfo = g_new0 (GdaDsnInfo, 1);
1146 		einfo->name = g_strdup (info->name);
1147 		if (info->provider)
1148 			einfo->provider = g_strdup (info->provider);
1149 		if (info->cnc_string)
1150 			einfo->cnc_string = g_strdup (info->cnc_string);
1151 		if (info->description)
1152 			einfo->description = g_strdup (info->description);
1153 		if (info->auth_string)
1154 			einfo->auth_string = g_strdup (info->auth_string);
1155 		einfo->is_system = info->is_system ? TRUE : FALSE;
1156 
1157 		unique_instance->priv->dsn_list = g_slist_insert_sorted (unique_instance->priv->dsn_list, einfo,
1158 									 (GCompareFunc) data_source_info_compare);
1159 		if (unique_instance->priv->emit_signals)
1160 			g_signal_emit (unique_instance, gda_config_signals[DSN_ADDED], 0, einfo);
1161 	}
1162 
1163 #ifdef HAVE_LIBSECRET
1164 	if (! info->is_system && info->auth_string) {
1165 		/* save to keyring */
1166 		gchar *tmp;
1167 		tmp = g_strdup_printf (_("Authentication for the '%s' DSN"), info->name);
1168 		if (sync_keyring) {
1169 			gboolean res;
1170 			GError *error = NULL;
1171 			res = secret_password_store_sync (SECRET_SCHEMA_COMPAT_NETWORK,
1172 							  SECRET_COLLECTION_DEFAULT,
1173 							  tmp, info->auth_string,
1174 							  NULL, &error,
1175 							  "server", info->name, NULL);
1176 			if (!res) {
1177 				gda_log_error (_("Couldn't save authentication information for DSN '%s': %s"),
1178 					       info->name,
1179 					       error && error->message ? error->message : _("No detail"));
1180 				g_clear_error (&error);
1181 			}
1182 		}
1183 		else {
1184 			secret_password_store (SECRET_SCHEMA_COMPAT_NETWORK,
1185 					       SECRET_COLLECTION_DEFAULT,
1186 					       tmp, info->auth_string,
1187 					       NULL,
1188 					       (GAsyncReadyCallback) secret_password_stored_cb,
1189 					       g_strdup (info->name),
1190 					       "server", info->name, NULL);
1191 		}
1192 		g_free (tmp);
1193 	}
1194 #else
1195   #ifdef HAVE_GNOME_KEYRING
1196 	if (! info->is_system && info->auth_string) {
1197 		/* save to keyring */
1198 		gchar *tmp;
1199 		tmp = g_strdup_printf (_("Authentication for the '%s' DSN"), info->name);
1200 		if (sync_keyring) {
1201 			GnomeKeyringResult res;
1202 			res = gnome_keyring_store_password_sync (GNOME_KEYRING_NETWORK_PASSWORD, GNOME_KEYRING_DEFAULT,
1203 								 tmp, info->auth_string,
1204 								 "server", info->name, NULL);
1205 			password_stored_cb (res, info->name);
1206 		}
1207 		else {
1208 			gchar *tmp1;
1209 			tmp1 = g_strdup (info->name);
1210 			gnome_keyring_store_password (GNOME_KEYRING_NETWORK_PASSWORD,
1211 						      GNOME_KEYRING_DEFAULT,
1212 						      tmp, info->auth_string,
1213 						      (GnomeKeyringOperationDoneCallback) password_stored_cb, tmp1, g_free,
1214 						      "server", info->name, NULL);
1215 		}
1216 		g_free (tmp);
1217 	}
1218   #endif
1219 #endif
1220 
1221 	if (save_system)
1222 		save_config_file (TRUE);
1223 	if (save_user)
1224 		save_config_file (FALSE);
1225 
1226 	GDA_CONFIG_UNLOCK ();
1227 	return TRUE;
1228 }
1229 
1230 #ifdef HAVE_LIBSECRET
1231 static void
1232 secret_password_deleted_cb (GObject *source_object, GAsyncResult *res, gchar *dsnname)
1233 {
1234 	GError *error = NULL;
1235 	if (! secret_password_clear_finish (res, &error)) {
1236                 gda_log_error (_("Couldn't delete authentication information for DSN '%s': %s"), dsnname,
1237 			       error && error->message ? error->message : _("No detail"));
1238 		g_clear_error (&error);
1239 	}
1240 	g_free (dsnname);
1241 }
1242 #else
1243   #ifdef HAVE_GNOME_KEYRING
1244 static void
1245 password_deleted_cb (GnomeKeyringResult res, const gchar *dsnname)
1246 {
1247 	if (res != GNOME_KEYRING_RESULT_OK)
1248                 gda_log_error (_("Couldn't delete authentication information for DSN '%s': %s"), dsnname,
1249 			       gnome_keyring_result_to_message (res));
1250 }
1251   #endif
1252 #endif
1253 
1254 /**
1255  * gda_config_remove_dsn:
1256  * @dsn_name: the name of the DSN to remove
1257  * @error: a place to store errors, or %NULL
1258  *
1259  * Remove the DSN named @dsn_name.
1260  *
1261  * This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
1262  *
1263  * Returns: TRUE if no error occurred
1264  */
1265 gboolean
1266 gda_config_remove_dsn (const gchar *dsn_name, GError **error)
1267 {
1268 	GdaDsnInfo *info;
1269 	gboolean save_user = FALSE;
1270 	gboolean save_system = FALSE;
1271 
1272 	g_return_val_if_fail (dsn_name, FALSE);
1273 
1274 	GDA_CONFIG_LOCK ();
1275 	if (!unique_instance)
1276 		gda_config_get ();
1277 
1278 	info = gda_config_get_dsn_info (dsn_name);
1279 	if (!info) {
1280 		g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_DSN_NOT_FOUND_ERROR,
1281 			     _("Unknown DSN '%s'"), dsn_name);
1282 		GDA_CONFIG_UNLOCK ();
1283 		return FALSE;
1284 	}
1285 	if (info->is_system && !unique_instance->priv->system_config_allowed) {
1286 		g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PERMISSION_ERROR,
1287 			      "%s", _("Can't manage system-wide configuration"));
1288 		GDA_CONFIG_UNLOCK ();
1289 		return FALSE;
1290 	}
1291 
1292 	if (info->is_system)
1293 		save_system = TRUE;
1294 	else
1295 		save_user = TRUE;
1296 
1297 	if (unique_instance->priv->emit_signals)
1298 		g_signal_emit (unique_instance, gda_config_signals[DSN_TO_BE_REMOVED], 0, info);
1299 	unique_instance->priv->dsn_list = g_slist_remove (unique_instance->priv->dsn_list, info);
1300 	if (unique_instance->priv->emit_signals)
1301 		g_signal_emit (unique_instance, gda_config_signals[DSN_REMOVED], 0, info);
1302 	data_source_info_free (info);
1303 
1304 #ifdef HAVE_LIBSECRET
1305 	if (! info->is_system) {
1306 		/* remove from keyring */
1307 		if (sync_keyring) {
1308 			GError *error = NULL;
1309 			if (! secret_password_clear_sync (SECRET_SCHEMA_COMPAT_NETWORK,
1310 							  NULL, &error,
1311 							  "server", info->name, NULL)) {
1312 				gda_log_error (_("Couldn't delete authentication information for DSN '%s': %s"),
1313 					       info->name,
1314 					       error && error->message ? error->message : _("No detail"));
1315 				g_clear_error (&error);
1316 			}
1317 		}
1318 		else {
1319 			secret_password_clear (SECRET_SCHEMA_COMPAT_NETWORK,
1320 					       NULL, (GAsyncReadyCallback) secret_password_deleted_cb,
1321 					       g_strdup (info->name),
1322 					       "server", info->name, NULL);
1323 		}
1324 	}
1325 #else
1326   #ifdef HAVE_GNOME_KEYRING
1327 	if (! info->is_system) {
1328 		/* remove from keyring */
1329 		if (sync_keyring) {
1330 			GnomeKeyringResult res;
1331 			res = gnome_keyring_delete_password_sync (GNOME_KEYRING_NETWORK_PASSWORD, GNOME_KEYRING_DEFAULT,
1332 								  "server", info->name, NULL);
1333 			password_deleted_cb (res, info->name);
1334 		}
1335 		else {
1336 			gchar *tmp;
1337 			tmp = g_strdup (dsn_name);
1338 			gnome_keyring_delete_password (GNOME_KEYRING_NETWORK_PASSWORD,
1339 						       (GnomeKeyringOperationDoneCallback) password_deleted_cb,
1340 						       tmp, g_free,
1341 						       "server", info->name, NULL);
1342 		}
1343 	}
1344   #endif
1345 #endif
1346 
1347 	if (save_system)
1348 		save_config_file (TRUE);
1349 	if (save_user)
1350 		save_config_file (FALSE);
1351 
1352 	GDA_CONFIG_UNLOCK ();
1353 	return TRUE;
1354 }
1355 
1356 /**
1357  * gda_config_dsn_needs_authentication:
1358  * @dsn_name: the name of a DSN, in the "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;" format
1359  *
1360  * Tells if the data source identified as @dsn_name needs any authentication. If a &lt;username&gt;
1361  * and optionally a &lt;password&gt; are specified, they are ignored.
1362  *
1363  * Returns: TRUE if an authentication is needed
1364  */
1365 gboolean
1366 gda_config_dsn_needs_authentication (const gchar *dsn_name)
1367 {
1368 	GdaDsnInfo *info;
1369 	GdaProviderInfo *pinfo;
1370 
1371 	info = gda_config_get_dsn_info (dsn_name);
1372 	if (!info)
1373 		return FALSE;
1374 	pinfo = gda_config_get_provider_info (info->provider);
1375 	if (!pinfo) {
1376 		gda_log_message (_("Provider '%s' not found"), info->provider);
1377 		return FALSE;
1378 	}
1379 	if (pinfo->auth_params && pinfo->auth_params->holders)
1380 		return TRUE;
1381 	else
1382 		return FALSE;
1383 }
1384 
1385 /**
1386  * gda_config_list_dsn:
1387  *
1388  * Get a #GdaDataModel representing all the configured DSN, and keeping itself up to date with
1389  * the changes in the declared DSN.
1390  *
1391  * The returned data model is composed of the following columns:
1392  * <itemizedlist>
1393  *  <listitem><para>DSN name</para></listitem>
1394  *  <listitem><para>Provider name</para></listitem>
1395  *  <listitem><para>Description</para></listitem>
1396  *  <listitem><para>Connection string</para></listitem>
1397  *  <listitem><para>Username if it exists</para></listitem>
1398  * </itemizedlist>
1399  *
1400  * Returns: (transfer full): a new #GdaDataModel
1401  */
1402 GdaDataModel *
1403 gda_config_list_dsn (void)
1404 {
1405 	GdaDataModel *model;
1406 	GDA_CONFIG_LOCK ();
1407 	if (!unique_instance)
1408 		gda_config_get ();
1409 
1410 	model = GDA_DATA_MODEL (g_object_new (GDA_TYPE_DATA_MODEL_DSN_LIST, NULL));
1411 	GDA_CONFIG_UNLOCK ();
1412 	return model;
1413 }
1414 
1415 /**
1416  * gda_config_get_nb_dsn:
1417  *
1418  * Get the number of defined DSN
1419  *
1420  * Returns: the number of defined DSN
1421  */
1422 gint
1423 gda_config_get_nb_dsn (void)
1424 {
1425 	gint ret;
1426 	GDA_CONFIG_LOCK ();
1427 	if (!unique_instance)
1428 		gda_config_get ();
1429 
1430 	ret = g_slist_length (unique_instance->priv->dsn_list);
1431 	GDA_CONFIG_UNLOCK ();
1432 	return ret;
1433 }
1434 
1435 /**
1436  * gda_config_get_dsn_info_index:
1437  * @dsn_name: a DSN
1438  *
1439  * Get the index (starting at 0) of the DSN named @dsn_name
1440  *
1441  * Returns: the index or -1 if not found
1442  */
1443 gint
1444 gda_config_get_dsn_info_index (const gchar *dsn_name)
1445 {
1446 	GdaDsnInfo *info;
1447 	gint ret = -1;
1448 
1449 	g_return_val_if_fail (dsn_name, -1);
1450 	GDA_CONFIG_LOCK ();
1451 	if (!unique_instance)
1452 		gda_config_get ();
1453 
1454 	info = gda_config_get_dsn_info (dsn_name);
1455 	if (info)
1456 		ret = g_slist_index (unique_instance->priv->dsn_list, info);
1457 
1458 	GDA_CONFIG_UNLOCK ();
1459 	return ret;
1460 }
1461 
1462 /**
1463  * gda_config_get_dsn_info_at_index:
1464  * @index: an index
1465  *
1466  * Get a pointer to a read-only #GdaDsnInfo at the @index position
1467  *
1468  * Returns: (transfer none):the pointer or %NULL if no DSN exists at position @index
1469  */
1470 GdaDsnInfo *
1471 gda_config_get_dsn_info_at_index (gint index)
1472 {
1473 	GdaDsnInfo *ret;
1474 	GDA_CONFIG_LOCK ();
1475 	if (!unique_instance)
1476 		gda_config_get ();
1477 	ret = g_slist_nth_data (unique_instance->priv->dsn_list, index);
1478 	GDA_CONFIG_UNLOCK ();
1479 	return ret;
1480 }
1481 
1482 /**
1483  * gda_config_can_modify_system_config:
1484  *
1485  * Tells if the global (system) configuration can be modified (considering
1486  * system permissions and settings)
1487  *
1488  * Returns: TRUE if system-wide configuration can be modified
1489  */
1490 gboolean
1491 gda_config_can_modify_system_config (void)
1492 {
1493 	gboolean retval;
1494 	GDA_CONFIG_LOCK ();
1495 	if (!unique_instance)
1496 		gda_config_get ();
1497 	retval = unique_instance->priv->system_config_allowed;
1498 	GDA_CONFIG_UNLOCK ();
1499 	return retval;
1500 }
1501 
1502 /**
1503  * gda_config_get_provider_info:
1504  * @provider_name: a database provider
1505  *
1506  * Get some information about the a database provider (adapter) named
1507  *
1508  * Returns: (transfer none): a pointer to read-only #GdaProviderInfo structure, or %NULL if not found
1509  */
1510 GdaProviderInfo *
1511 gda_config_get_provider_info (const gchar *provider_name)
1512 {
1513 	GSList *list;
1514 	g_return_val_if_fail (provider_name, NULL);
1515 	GDA_CONFIG_LOCK ();
1516 	if (!unique_instance)
1517 		gda_config_get ();
1518 
1519 	if (!unique_instance->priv->providers_loaded)
1520 		load_all_providers ();
1521 
1522 	if (!g_ascii_strcasecmp (provider_name, "MS Access")) {
1523 		GDA_CONFIG_UNLOCK ();
1524 		return gda_config_get_provider_info ("MSAccess");
1525 	}
1526 
1527 	for (list = unique_instance->priv->prov_list; list; list = list->next)
1528 		if (!g_ascii_strcasecmp (((GdaProviderInfo*) list->data)->id, provider_name)) {
1529 			GDA_CONFIG_UNLOCK ();
1530 			return (GdaProviderInfo*) list->data;
1531 		}
1532 	GDA_CONFIG_UNLOCK ();
1533 	return NULL;
1534 }
1535 
1536 /**
1537  * gda_config_get_provider:
1538  * @provider_name: a database provider
1539  * @error: a place to store errors, or %NULL
1540  *
1541  * Get a pointer to the session-wide #GdaServerProvider for the
1542  * provider named @provider_name. The caller must not call g_object_unref() on the
1543  * returned object.
1544  *
1545  * This method may fail with a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
1546  *
1547  * Returns: (transfer none): a pointer to the #GdaServerProvider, or %NULL if an error occurred
1548  */
1549 GdaServerProvider *
1550 gda_config_get_provider (const gchar *provider_name, GError **error)
1551 {
1552 	InternalProvider *ip;
1553 	GdaServerProvider  *(*plugin_create_provider) (void);
1554 	GdaServerProvider  *(*plugin_create_sub_provider) (const gchar *provider_name);
1555 
1556 	g_return_val_if_fail (provider_name, NULL);
1557 	GDA_CONFIG_LOCK ();
1558 	ip = (InternalProvider *) gda_config_get_provider_info (provider_name);
1559 	if (!ip) {
1560 		g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR,
1561 			     _("No provider '%s' installed"), provider_name);
1562 		GDA_CONFIG_UNLOCK ();
1563 		return NULL;
1564 	}
1565 	if (ip->instance) {
1566 		GDA_CONFIG_UNLOCK ();
1567 		return ip->instance;
1568 	}
1569 
1570 	/* need to actually create the provider object */
1571 	if (!ip->handle) {
1572 		GdaProviderInfo *info = (GdaProviderInfo*) ip;
1573 		ip->handle = g_module_open (info->location, G_MODULE_BIND_LAZY);
1574 		if (!ip->handle) {
1575 			g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_CREATION_ERROR,
1576 				     _("Can't load provider: %s"), g_module_error ());
1577 			return NULL;
1578 		}
1579 
1580 		void (*plugin_init) (const gchar *);
1581 		if (g_module_symbol (ip->handle, "plugin_init", (gpointer *) &plugin_init)) {
1582 			gchar *dirname = g_path_get_dirname (info->location);
1583 			plugin_init (dirname);
1584 			g_free (dirname);
1585 		}
1586 	}
1587 
1588 	g_module_symbol (ip->handle, "plugin_create_provider", (gpointer) &plugin_create_provider);
1589 	if (plugin_create_provider)
1590 		ip->instance = plugin_create_provider ();
1591 	else {
1592 		g_module_symbol (ip->handle, "plugin_create_sub_provider", (gpointer) &plugin_create_sub_provider);
1593 		if (plugin_create_sub_provider)
1594 			ip->instance = plugin_create_sub_provider (provider_name);
1595 	}
1596 
1597 	if (!ip->instance) {
1598 		g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_CREATION_ERROR,
1599 			     _("Can't instantiate provider '%s'"), provider_name);
1600 		GDA_CONFIG_UNLOCK ();
1601 		return NULL;
1602 	}
1603 
1604 	GDA_CONFIG_UNLOCK ();
1605 	return ip->instance;
1606 }
1607 
1608 /**
1609  * gda_config_list_providers:
1610  *
1611  * Get a #GdaDataModel representing all the installed database providers.
1612  *
1613  * The returned data model is composed of the following columns:
1614  * <itemizedlist>
1615  *  <listitem><para>Provider name</para></listitem>
1616  *  <listitem><para>Description</para></listitem>
1617  *  <listitem><para>DSN parameters</para></listitem>
1618  *  <listitem><para>Authentication parameters</para></listitem>
1619  *  <listitem><para>File name of the plugin</para></listitem>
1620  * </itemizedlist>
1621  *
1622  * Returns: (transfer full): a new #GdaDataModel
1623  */
1624 GdaDataModel *
1625 gda_config_list_providers (void)
1626 {
1627 	GSList *list;
1628 	GdaDataModel *model;
1629 
1630 	GDA_CONFIG_LOCK ();
1631 	if (!unique_instance)
1632 		gda_config_get ();
1633 
1634 	if (!unique_instance->priv->providers_loaded)
1635 		load_all_providers ();
1636 
1637 	model = gda_data_model_array_new_with_g_types (5,
1638 						       G_TYPE_STRING,
1639 						       G_TYPE_STRING,
1640 						       G_TYPE_STRING,
1641 						       G_TYPE_STRING,
1642 						       G_TYPE_STRING);
1643 	gda_data_model_set_column_title (model, 0, _("Provider"));
1644 	gda_data_model_set_column_title (model, 1, _("Description"));
1645 	gda_data_model_set_column_title (model, 2, _("DSN parameters"));
1646 	gda_data_model_set_column_title (model, 3, _("Authentication"));
1647 	gda_data_model_set_column_title (model, 4, _("File"));
1648 	g_object_set_data (G_OBJECT (model), "name", _("List of installed providers"));
1649 
1650 	for (list = unique_instance->priv->prov_list; list; list = list->next) {
1651 		GdaProviderInfo *info = (GdaProviderInfo *) list->data;
1652 		GValue *value;
1653 		gint row;
1654 
1655 		row = gda_data_model_append_row (model, NULL);
1656 
1657 		value = gda_value_new_from_string (info->id, G_TYPE_STRING);
1658 		gda_data_model_set_value_at (model, 0, row, value, NULL);
1659 		gda_value_free (value);
1660 
1661 		if (info->description)
1662 			value = gda_value_new_from_string (info->description, G_TYPE_STRING);
1663 		else
1664 			value = gda_value_new_null ();
1665 		gda_data_model_set_value_at (model, 1, row, value, NULL);
1666 		gda_value_free (value);
1667 
1668 		if (info->dsn_params) {
1669 			GSList *params;
1670 			GString *string = g_string_new ("");
1671 			for (params = info->dsn_params->holders;
1672 			     params; params = params->next) {
1673 				const gchar *id;
1674 
1675 				id = gda_holder_get_id (GDA_HOLDER (params->data));
1676 				if (params != info->dsn_params->holders)
1677 					g_string_append (string, ",\n");
1678 				g_string_append (string, id);
1679 			}
1680 			value = gda_value_new_from_string (string->str, G_TYPE_STRING);
1681 			g_string_free (string, TRUE);
1682 			gda_data_model_set_value_at (model, 2, row, value, NULL);
1683 			gda_value_free (value);
1684 		}
1685 
1686 		if (info->auth_params) {
1687 			GSList *params;
1688 			GString *string = g_string_new ("");
1689 			for (params = info->auth_params->holders;
1690 			     params; params = params->next) {
1691 				const gchar *id;
1692 
1693 				id = gda_holder_get_id (GDA_HOLDER (params->data));
1694 				if (params != info->auth_params->holders)
1695 					g_string_append (string, ",\n");
1696 				g_string_append (string, id);
1697 			}
1698 			value = gda_value_new_from_string (string->str, G_TYPE_STRING);
1699 			g_string_free (string, TRUE);
1700 			gda_data_model_set_value_at (model, 3, row, value, NULL);
1701 			gda_value_free (value);
1702 		}
1703 
1704 		value = gda_value_new_from_string (info->location, G_TYPE_STRING);
1705 		gda_data_model_set_value_at (model, 4, row, value, NULL);
1706 		gda_value_free (value);
1707 	}
1708 	g_object_set (G_OBJECT (model), "read-only", TRUE, NULL);
1709 
1710 	GDA_CONFIG_UNLOCK ();
1711 	return model;
1712 }
1713 
1714 static gint
1715 internal_provider_sort_func (InternalProvider *a, InternalProvider *b)
1716 {
1717 	return strcmp (a->pinfo.id, b->pinfo.id);
1718 }
1719 
1720 static void load_providers_from_dir (const gchar *dirname, gboolean recurs);
1721 static void
1722 load_all_providers (void)
1723 {
1724 	const gchar *dirname;
1725 	g_assert (unique_instance);
1726 
1727 	dirname = g_getenv ("GDA_TOP_BUILD_DIR");
1728 	if (dirname) {
1729 		gchar *pdir;
1730 		pdir = g_build_path (G_DIR_SEPARATOR_S, dirname, "providers", NULL);
1731 		load_providers_from_dir (pdir, TRUE);
1732 		g_free (pdir);
1733 	}
1734 	else {
1735 		gchar *str;
1736 		str = gda_gbr_get_file_path (GDA_LIB_DIR, LIBGDA_ABI_NAME, "providers", NULL);
1737 		load_providers_from_dir (str, FALSE);
1738 		g_free (str);
1739 	}
1740 	unique_instance->priv->providers_loaded = TRUE;
1741 
1742 	/* find SQLite provider, and instantiate it if not installed */
1743 	_gda_config_sqlite_provider = gda_config_get_provider ("SQLite", NULL);
1744 	if (!_gda_config_sqlite_provider) {
1745 		_gda_config_sqlite_provider = (GdaServerProvider*)
1746 			g_object_new (GDA_TYPE_SQLITE_PROVIDER, NULL);
1747 	}
1748 
1749 	/* sort providers by name */
1750 	unique_instance->priv->prov_list = g_slist_sort (unique_instance->priv->prov_list,
1751 							 (GCompareFunc) internal_provider_sort_func);
1752 }
1753 
1754 static InternalProvider *
1755 create_internal_provider (const gchar *path,
1756 			  const gchar *prov_name, const gchar *prov_descr,
1757 			  gchar *dsn_spec, gchar *auth_spec)
1758 {
1759 	InternalProvider *ip;
1760 	GdaProviderInfo *info;
1761 
1762 	ip = g_new0 (InternalProvider, 1);
1763 	ip->handle = NULL;
1764 	info = (GdaProviderInfo*) ip;
1765 	info->location = g_strdup (path);
1766 
1767 	info->id = g_strdup (prov_name);
1768 	info->description = g_strdup (prov_descr);
1769 
1770 	/* DSN parameters */
1771 	info->dsn_params = NULL;
1772 	if (dsn_spec) {
1773 		GError *error = NULL;
1774 		info->dsn_params = gda_set_new_from_spec_string (dsn_spec, &error);
1775 		if (!info->dsn_params) {
1776 			gda_log_message ("Invalid format for provider '%s' DSN spec : %s",
1777 					 info->id,
1778 					 error ? error->message : "Unknown error");
1779 			g_clear_error (&error);
1780 
1781 			/* there may be traces of the provider installed but some parts are missing,
1782 			   forget about that provider... */
1783 			internal_provider_free (ip);
1784 			g_free (dsn_spec);
1785 			return NULL;
1786 		}
1787 		g_free (dsn_spec);
1788 	}
1789 	else
1790 		gda_log_message ("Provider '%s' does not provide a DSN spec", info->id);
1791 
1792 	/* Authentication parameters */
1793 	info->auth_params = NULL;
1794 	if (auth_spec) {
1795 		GError *error = NULL;
1796 
1797 		info->auth_params = gda_set_new_from_spec_string (auth_spec, &error);
1798 		if (!info->auth_params) {
1799 			gda_log_message ("Invalid format for provider '%s' AUTH spec : %s",
1800 					 info->id,
1801 				   error ? error->message : "Unknown error");
1802 			if (error)
1803 				g_error_free (error);
1804 		}
1805 
1806 		if (!info->auth_params) {
1807 			/* there may be traces of the provider installed but some parts are missing,
1808 			   forget about that provider... */
1809 			internal_provider_free (ip);
1810 			g_free (auth_spec);
1811 			return NULL;
1812 		}
1813 		g_free (auth_spec);
1814 	}
1815 	else {
1816 		/* default to username/password */
1817 		GdaHolder *h;
1818 		info->auth_params = gda_set_new_inline (2, "USERNAME", G_TYPE_STRING, NULL,
1819 							"PASSWORD", G_TYPE_STRING, NULL);
1820 		h = gda_set_get_holder (info->auth_params, "USERNAME");
1821 		g_object_set (G_OBJECT (h), "name", _("Username"), "not-null", TRUE, NULL);
1822 		h = gda_set_get_holder (info->auth_params, "PASSWORD");
1823 		g_object_set (G_OBJECT (h), "name", _("Password"), "not-null", TRUE, NULL);
1824 
1825 		GValue *value;
1826 #define GDAUI_ATTRIBUTE_PLUGIN "__gdaui_attr_plugin"
1827 		value = gda_value_new_from_string ("string:HIDDEN=true", G_TYPE_STRING);
1828                 gda_holder_set_attribute_static (h, GDAUI_ATTRIBUTE_PLUGIN, value);
1829                 gda_value_free (value);
1830 	}
1831 	return ip;
1832 }
1833 
1834 static void
1835 load_providers_from_dir (const gchar *dirname, gboolean recurs)
1836 {
1837 	GDir *dir;
1838 	GError *err = NULL;
1839 	const gchar *name;
1840 
1841 	/* read the plugin directory */
1842 #ifdef GDA_DEBUG_NO
1843 	g_print ("Loading providers in %s\n", dirname);
1844 #endif
1845 	dir = g_dir_open (dirname, 0, &err);
1846 	if (err) {
1847 		gda_log_error (err->message);
1848 		g_error_free (err);
1849 		return;
1850 	}
1851 
1852 	while ((name = g_dir_read_name (dir))) {
1853 		GModule *handle;
1854 		gchar *path;
1855 
1856 		/* initialization method */
1857 		void (*plugin_init) (const gchar *);
1858 
1859 		/* methods for shared libraries which provide only one type of provider */
1860 		const gchar * (* plugin_get_name) (void);
1861 		const gchar * (* plugin_get_description) (void);
1862 		gchar * (* plugin_get_dsn_spec) (void);
1863 		gchar * (* plugin_get_auth_spec) (void);
1864 
1865 		/* methods for shared libraries which provide several types of providers (ODBC, JDBC, ...) */
1866 		const gchar ** (* plugin_get_sub_names) (void);
1867 		const gchar * (* plugin_get_sub_description) (const gchar *name);
1868 		gchar * (* plugin_get_sub_dsn_spec) (const gchar *name);
1869 		gchar * (* plugin_get_sub_auth_spec) (const gchar *name);
1870 
1871 		if (recurs) {
1872 			gchar *cname;
1873 			cname = g_build_filename (dirname, name, NULL);
1874 			if (g_file_test (cname, G_FILE_TEST_IS_DIR))
1875 				load_providers_from_dir (cname, TRUE);
1876 			g_free (cname);
1877 		}
1878 
1879 		if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX))
1880 			continue;
1881 #ifdef G_WITH_CYGWIN
1882 		if (!g_str_has_prefix (name, "cyggda"))
1883 #else
1884 		if (!g_str_has_prefix (name, "libgda"))
1885 #endif
1886 			continue;
1887 
1888 		path = g_build_path (G_DIR_SEPARATOR_S, dirname,
1889 				     name, NULL);
1890 		handle = g_module_open (path, G_MODULE_BIND_LAZY);
1891 		if (!handle) {
1892 			if (g_getenv ("GDA_SHOW_PROVIDER_LOADING_ERROR"))
1893 				gda_log_message (_("Error loading provider '%s': %s"), path, g_module_error ());
1894 			g_free (path);
1895 			continue;
1896 		}
1897 
1898 		if (g_module_symbol (handle, "plugin_init", (gpointer *) &plugin_init)) {
1899 			plugin_init (dirname);
1900 		}
1901 		else {
1902 			g_module_close (handle);
1903 			g_free (path);
1904 			continue;
1905 		}
1906 		g_module_symbol (handle, "plugin_get_name",
1907 				 (gpointer *) &plugin_get_name);
1908 		g_module_symbol (handle, "plugin_get_description",
1909 				 (gpointer *) &plugin_get_description);
1910 		g_module_symbol (handle, "plugin_get_dsn_spec",
1911 				 (gpointer *) &plugin_get_dsn_spec);
1912 		g_module_symbol (handle, "plugin_get_auth_spec",
1913 				 (gpointer *) &plugin_get_auth_spec);
1914 		g_module_symbol (handle, "plugin_get_sub_names",
1915 				 (gpointer *) &plugin_get_sub_names);
1916 		g_module_symbol (handle, "plugin_get_sub_description",
1917 				 (gpointer *) &plugin_get_sub_description);
1918 		g_module_symbol (handle, "plugin_get_sub_dsn_spec",
1919 				 (gpointer *) &plugin_get_sub_dsn_spec);
1920 		g_module_symbol (handle, "plugin_get_sub_auth_spec",
1921 				 (gpointer *) &plugin_get_sub_auth_spec);
1922 
1923 		if (plugin_get_sub_names) {
1924 			const gchar **subnames = plugin_get_sub_names ();
1925 			const gchar **ptr;
1926 			for (ptr = subnames; ptr && *ptr; ptr++) {
1927 				InternalProvider *ip;
1928 
1929 				ip = create_internal_provider (path, *ptr,
1930 							       plugin_get_sub_description ?
1931 							       plugin_get_sub_description (*ptr) : NULL,
1932 							       plugin_get_sub_dsn_spec ?
1933 							       plugin_get_sub_dsn_spec (*ptr) : NULL,
1934 							       plugin_get_sub_auth_spec ?
1935 							       plugin_get_sub_auth_spec (*ptr) : NULL);
1936 				if (ip) {
1937 					unique_instance->priv->prov_list =
1938 						g_slist_prepend (unique_instance->priv->prov_list, ip);
1939 #ifdef GDA_DEBUG_NO
1940 					g_print ("Loaded '%s' sub-provider\n", ((GdaProviderInfo*) ip)->id);
1941 #endif
1942 				}
1943 			}
1944 		}
1945 		else {
1946 			InternalProvider *ip;
1947 			ip = create_internal_provider (path,
1948 						       plugin_get_name ? plugin_get_name () : name,
1949 						       plugin_get_description ? plugin_get_description () : NULL,
1950 						       plugin_get_dsn_spec ? plugin_get_dsn_spec () : NULL,
1951 						       plugin_get_auth_spec ? plugin_get_auth_spec () : NULL);
1952 			if (ip) {
1953 				unique_instance->priv->prov_list =
1954 					g_slist_prepend (unique_instance->priv->prov_list, ip);
1955 #ifdef GDA_DEBUG_NO
1956 				g_print ("Loaded '%s' provider\n", ((GdaProviderInfo*) ip)->id);
1957 #endif
1958 			}
1959 		}
1960 		g_free (path);
1961 		g_module_close (handle);
1962 	}
1963 
1964 	/* free memory */
1965 	g_dir_close (dir);
1966 }
1967 
1968 
1969 
1970 /* sorting function */
1971 static gint
1972 data_source_info_compare (GdaDsnInfo *infoa, GdaDsnInfo *infob)
1973 {
1974 	if (!infoa && !infob)
1975 		return 0;
1976 	if (infoa) {
1977 		if (!infob)
1978 			return 1;
1979 		else {
1980 			gchar *u8a, *u8b;
1981 			gint res;
1982 			u8a = g_utf8_casefold (infoa->name, -1);
1983 			u8b = g_utf8_casefold (infob->name, -1);
1984 			res = strcmp (u8a, u8b);
1985 			g_free (u8a);
1986 			g_free (u8b);
1987 			return res;
1988 		}
1989 	}
1990 	else
1991 		return -1;
1992 }
1993 
1994 static void
1995 data_source_info_free (GdaDsnInfo *info)
1996 {
1997 	g_free (info->provider);
1998 	g_free (info->cnc_string);
1999 	g_free (info->description);
2000 	g_free (info->auth_string);
2001 	g_free (info);
2002 }
2003 
2004 static void
2005 internal_provider_free (InternalProvider *ip)
2006 {
2007 	GdaProviderInfo *info = (GdaProviderInfo*) ip;
2008 	if (ip->instance)
2009 		g_object_unref (ip->instance);
2010 	if (ip->handle)
2011 		g_module_close (ip->handle);
2012 
2013 	g_free (info->id);
2014 	g_free (info->location);
2015 	g_free (info->description);
2016 	if (info->dsn_params)
2017 		g_object_unref (info->dsn_params);
2018 	g_free (ip);
2019 }
2020 
2021 static gboolean
2022 str_equal (const gchar *str1, const gchar *str2)
2023 {
2024 	if (str1 && str2) {
2025 		if (!strcmp (str1, str2))
2026 			return TRUE;
2027 		else
2028 			return FALSE;
2029 	}
2030 	else if (!str1 && !str2)
2031 		return TRUE;
2032 	return FALSE;
2033 }
2034 
2035 static void
2036 reload_dsn_configuration (void)
2037 {
2038 	GSList *list, *current_dsn_list, *new_dsn_list;
2039 	if (!unique_instance) {
2040 		/* object not yet created */
2041 		return;
2042 	}
2043 
2044         GDA_CONFIG_LOCK ();
2045 #ifdef GDA_DEBUG_NO
2046 	gboolean is_system = (mon == mon_conf_global) ? TRUE : FALSE;
2047 	g_print ("Reloading config files (%s config has changed)\n", is_system ? "global" : "user");
2048 	for (list = unique_instance->priv->dsn_list; list; list = list->next) {
2049 		GdaDsnInfo *info = (GdaDsnInfo *) list->data;
2050 		g_print ("[info %p]: %s/%s\n", info, info->provider, info->name);
2051 	}
2052 #endif
2053 	current_dsn_list = unique_instance->priv->dsn_list;
2054 	unique_instance->priv->dsn_list = NULL;
2055 
2056 	unique_instance->priv->emit_signals = FALSE;
2057 #ifdef HAVE_GIO
2058 	lock_notify_changes ();
2059 #endif
2060 	if (unique_instance->priv->system_file)
2061 		load_config_file (unique_instance->priv->system_file, TRUE);
2062 	if (unique_instance->priv->user_file)
2063 		load_config_file (unique_instance->priv->user_file, FALSE);
2064 #ifdef HAVE_GIO
2065 	unlock_notify_changes ();
2066 #endif
2067 	unique_instance->priv->emit_signals = TRUE;
2068 
2069 	new_dsn_list = unique_instance->priv->dsn_list;
2070 	unique_instance->priv->dsn_list = current_dsn_list;
2071 	current_dsn_list = NULL;
2072 
2073 	/* handle new or updated DSN */
2074 	GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
2075 	for (list = new_dsn_list; list; list = list->next) {
2076 		GdaDsnInfo *ninfo, *oinfo;
2077 		ninfo = (GdaDsnInfo *) list->data;
2078 		oinfo = gda_config_get_dsn_info (ninfo->name);
2079 		if (!oinfo) {
2080 			/* add ninfo */
2081 			unique_instance->priv->dsn_list = g_slist_insert_sorted (unique_instance->priv->dsn_list, ninfo,
2082 										 (GCompareFunc) data_source_info_compare);
2083 			if (unique_instance->priv->emit_signals)
2084 				g_signal_emit (unique_instance, gda_config_signals[DSN_ADDED], 0, ninfo);
2085 			g_hash_table_insert (hash, ninfo->name, (gpointer) 0x1);
2086 		}
2087 		else {
2088 			/* signal changed if updated */
2089 			if (str_equal (oinfo->provider, ninfo->provider) &&
2090 			    str_equal (oinfo->description, ninfo->description) &&
2091 			    str_equal (oinfo->cnc_string, ninfo->cnc_string) &&
2092 #if !defined (HAVE_GNOME_KEYRING) && !defined (HAVE_LIBSECRET)
2093 			    str_equal (oinfo->auth_string, ninfo->auth_string) &&
2094 #endif
2095 			    (oinfo->is_system == ninfo->is_system)) {
2096 				/* no change for this DSN */
2097 				data_source_info_free (ninfo);
2098 			}
2099 			else {
2100 				GdaDsnInfo tmp;
2101 				tmp = *oinfo;
2102 				*oinfo = *ninfo;
2103 				*ninfo = tmp;
2104 				if (unique_instance->priv->emit_signals)
2105 					g_signal_emit (unique_instance, gda_config_signals[DSN_CHANGED], 0, oinfo);
2106 				data_source_info_free (ninfo);
2107 			}
2108 			g_hash_table_insert (hash, oinfo->name, (gpointer) 0x1);
2109 		}
2110 	}
2111 	g_slist_free (new_dsn_list);
2112 
2113 	/* remove old DSN */
2114 	for (list = unique_instance->priv->dsn_list; list; ) {
2115 		GdaDsnInfo *info;
2116 		info = (GdaDsnInfo *) list->data;
2117 		list = list->next;
2118 		if (g_hash_table_lookup (hash, info->name))
2119 			continue;
2120 
2121 		if (unique_instance->priv->emit_signals)
2122 			g_signal_emit (unique_instance, gda_config_signals[DSN_TO_BE_REMOVED], 0, info);
2123 		unique_instance->priv->dsn_list = g_slist_remove (unique_instance->priv->dsn_list, info);
2124 		if (unique_instance->priv->emit_signals)
2125 			g_signal_emit (unique_instance, gda_config_signals[DSN_REMOVED], 0, info);
2126 		data_source_info_free (info);
2127 	}
2128 	g_hash_table_destroy (hash);
2129 
2130         GDA_CONFIG_UNLOCK ();
2131 }
2132 
2133 /*
2134  * File monitoring actions
2135  */
2136 #ifdef HAVE_GIO
2137 
2138 static void
2139 conf_file_changed (G_GNUC_UNUSED GFileMonitor *mon, G_GNUC_UNUSED GFile *file,
2140 		   G_GNUC_UNUSED GFile *other_file, GFileMonitorEvent event_type,
2141 		   G_GNUC_UNUSED gpointer data)
2142 {
2143 	if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
2144 		return;
2145 	reload_dsn_configuration ();
2146 }
2147 
2148 static void
2149 lock_notify_changes (void)
2150 {
2151 	if (user_notify_changes != 0)
2152 		g_signal_handler_block (mon_conf_user, user_notify_changes);
2153 	if (global_notify_changes != 0)
2154 		g_signal_handler_block (mon_conf_global, global_notify_changes);
2155 }
2156 
2157 static void
2158 unlock_notify_changes (void)
2159 {
2160 	if (user_notify_changes != 0)
2161 		g_signal_handler_unblock (mon_conf_user, user_notify_changes);
2162 	if (global_notify_changes != 0)
2163 		g_signal_handler_unblock (mon_conf_global, global_notify_changes);
2164 }
2165 
2166 #endif
2167