1 /*
2  * Copyright (C) 2011 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 <libgda/libgda.h>
22 #include "gda-tree-mgr-ldap.h"
23 #include "gda-tree-node.h"
24 #include <sqlite/virtual/gda-ldap-connection.h>
25 
26 struct _GdaTreeMgrLdapPriv {
27 	GdaLdapConnection *cnc;
28 	gchar             *dn;
29 };
30 
31 static void gda_tree_mgr_ldap_class_init (GdaTreeMgrLdapClass *klass);
32 static void gda_tree_mgr_ldap_init       (GdaTreeMgrLdap *tmgr1, GdaTreeMgrLdapClass *klass);
33 static void gda_tree_mgr_ldap_dispose    (GObject *object);
34 static void gda_tree_mgr_ldap_set_property (GObject *object,
35 					    guint param_id,
36 					    const GValue *value,
37 					    GParamSpec *pspec);
38 static void gda_tree_mgr_ldap_get_property (GObject *object,
39 					    guint param_id,
40 					    GValue *value,
41 					    GParamSpec *pspec);
42 
43 /* virtual methods */
44 static GSList *gda_tree_mgr_ldap_update_children (GdaTreeManager *manager, GdaTreeNode *node, const GSList *children_nodes,
45 						  gboolean *out_error, GError **error);
46 
47 static GObjectClass *parent_class = NULL;
48 
49 /* properties */
50 enum {
51         PROP_0,
52 	PROP_CNC,
53 	PROP_DN,
54 };
55 
56 /*
57  * GdaTreeMgrLdap class implementation
58  * @klass:
59  */
60 static void
gda_tree_mgr_ldap_class_init(GdaTreeMgrLdapClass * klass)61 gda_tree_mgr_ldap_class_init (GdaTreeMgrLdapClass *klass)
62 {
63 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
64 
65 	parent_class = g_type_class_peek_parent (klass);
66 
67 	/* virtual methods */
68 	((GdaTreeManagerClass*) klass)->update_children = gda_tree_mgr_ldap_update_children;
69 
70 	/* Properties */
71         object_class->set_property = gda_tree_mgr_ldap_set_property;
72         object_class->get_property = gda_tree_mgr_ldap_get_property;
73 
74 	/**
75 	 * GdaTreeMgrLdap:connection:
76 	 *
77 	 * Defines the #GdaLdapConnection to get information from.
78 	 */
79 	g_object_class_install_property (object_class, PROP_CNC,
80                                          g_param_spec_object ("connection", NULL, "Connection to use",
81                                                               GDA_TYPE_LDAP_CONNECTION,
82                                                               G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
83 
84 	/**
85 	 * GdaTreeMgrLdap:dn:
86 	 *
87 	 * Defines the Distinguised Name of the LDAP entry to list children from
88 	 */
89 	g_object_class_install_property (object_class, PROP_DN,
90                                          g_param_spec_string ("dn", NULL, "Distinguised Name",
91 							      NULL,
92                                                               G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
93 	object_class->dispose = gda_tree_mgr_ldap_dispose;
94 }
95 
96 static void
gda_tree_mgr_ldap_init(GdaTreeMgrLdap * mgr,G_GNUC_UNUSED GdaTreeMgrLdapClass * klass)97 gda_tree_mgr_ldap_init (GdaTreeMgrLdap *mgr, G_GNUC_UNUSED GdaTreeMgrLdapClass *klass)
98 {
99 	g_return_if_fail (GDA_IS_TREE_MGR_LDAP (mgr));
100 	mgr->priv = g_new0 (GdaTreeMgrLdapPriv, 1);
101 }
102 
103 static void
gda_tree_mgr_ldap_dispose(GObject * object)104 gda_tree_mgr_ldap_dispose (GObject *object)
105 {
106 	GdaTreeMgrLdap *mgr = (GdaTreeMgrLdap *) object;
107 
108 	g_return_if_fail (GDA_IS_TREE_MGR_LDAP (mgr));
109 
110 	if (mgr->priv) {
111 		if (mgr->priv->cnc)
112 			g_object_unref (mgr->priv->cnc);
113 		g_free (mgr->priv->dn);
114 		g_free (mgr->priv);
115 		mgr->priv = NULL;
116 	}
117 
118 	/* chain to parent class */
119 	parent_class->dispose (object);
120 }
121 
122 /**
123  * gda_tree_mgr_ldap_get_type:
124  *
125  * Returns: the GType
126  *
127  * Since: 4.2.8
128  */
129 GType
gda_tree_mgr_ldap_get_type(void)130 gda_tree_mgr_ldap_get_type (void)
131 {
132         static GType type = 0;
133 
134         if (G_UNLIKELY (type == 0)) {
135                 static GMutex registering;
136                 static const GTypeInfo info = {
137                         sizeof (GdaTreeMgrLdapClass),
138                         (GBaseInitFunc) NULL,
139                         (GBaseFinalizeFunc) NULL,
140                         (GClassInitFunc) gda_tree_mgr_ldap_class_init,
141                         NULL,
142                         NULL,
143                         sizeof (GdaTreeMgrLdap),
144                         0,
145                         (GInstanceInitFunc) gda_tree_mgr_ldap_init,
146 			0
147                 };
148 
149                 g_mutex_lock (&registering);
150                 if (type == 0)
151                         type = g_type_register_static (GDA_TYPE_TREE_MANAGER, "GdaTreeMgrLdap", &info, 0);
152                 g_mutex_unlock (&registering);
153         }
154         return type;
155 }
156 
157 static void
gda_tree_mgr_ldap_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)158 gda_tree_mgr_ldap_set_property (GObject *object,
159 				guint param_id,
160 				const GValue *value,
161 				GParamSpec *pspec)
162 {
163         GdaTreeMgrLdap *mgr;
164 
165         mgr = GDA_TREE_MGR_LDAP (object);
166         if (mgr->priv) {
167                 switch (param_id) {
168 		case PROP_CNC:
169 			mgr->priv->cnc = (GdaLdapConnection*) g_value_get_object (value);
170 			if (mgr->priv->cnc)
171 				g_object_ref (mgr->priv->cnc);
172 			break;
173 		case PROP_DN:
174                         mgr->priv->dn = g_value_dup_string (value);
175                         break;
176 		default:
177 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
178 			break;
179                 }
180         }
181 }
182 
183 static void
gda_tree_mgr_ldap_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)184 gda_tree_mgr_ldap_get_property (GObject *object,
185 				guint param_id,
186 				GValue *value,
187 				GParamSpec *pspec)
188 {
189         GdaTreeMgrLdap *mgr;
190 
191         mgr = GDA_TREE_MGR_LDAP (object);
192         if (mgr->priv) {
193                 switch (param_id) {
194 		case PROP_CNC:
195 			g_value_set_object (value, mgr->priv->cnc);
196 			break;
197 		case PROP_DN:
198 			g_value_set_string (value, mgr->priv->dn);
199                         break;
200 		default:
201 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
202 			break;
203                 }
204         }
205 }
206 
207 /**
208  * gda_tree_mgr_ldap_new:
209  * @cnc: a #GdaConnection object
210  * @dn: (allow-none): an LDAP Distinguished Name or %NULL
211  *
212  * Creates a new #GdaTreeManager object which will list the children of the LDAP entry which Distinguished name
213  * is @dn. If @dn is %NULL, then the tree manager will look in the tree itself for an attribute named "dn" and
214  * use it.
215  *
216  * Returns: (transfer full): a new #GdaTreeManager object
217  *
218  * Since: 4.2.8
219  */
220 GdaTreeManager*
gda_tree_mgr_ldap_new(GdaConnection * cnc,const gchar * dn)221 gda_tree_mgr_ldap_new (GdaConnection *cnc, const gchar *dn)
222 {
223 	GdaTreeMgrLdap *mgr;
224 	g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
225 
226 	mgr = (GdaTreeMgrLdap*) g_object_new (GDA_TYPE_TREE_MGR_LDAP,
227 					      "connection", cnc,
228 					      "dn", dn, NULL);
229 	return (GdaTreeManager*) mgr;
230 }
231 
232 static GSList *
gda_tree_mgr_ldap_update_children(GdaTreeManager * manager,GdaTreeNode * node,G_GNUC_UNUSED const GSList * children_nodes,gboolean * out_error,GError ** error)233 gda_tree_mgr_ldap_update_children (GdaTreeManager *manager, GdaTreeNode *node,
234 				   G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error,
235 				   GError **error)
236 {
237 	GdaTreeMgrLdap *mgr = GDA_TREE_MGR_LDAP (manager);
238 	gchar *real_dn = NULL;
239 
240 	if (!mgr->priv->cnc) {
241 		g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR,
242 			     _("No LDAP connection specified"));
243 		if (out_error)
244 			*out_error = TRUE;
245 		return NULL;
246 	}
247 
248 	if (mgr->priv->dn)
249 		real_dn = g_strdup (mgr->priv->dn);
250 	else if (node) {
251 		/* looking for a dn in @node's attributes */
252 		const GValue *cvalue;
253 		cvalue = gda_tree_node_fetch_attribute (node, "dn");
254 		if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_STRING))
255 			real_dn = g_value_dup_string (cvalue);
256 	}
257 
258 	GdaLdapEntry **entries;
259 	entries = gda_ldap_get_entry_children (mgr->priv->cnc, real_dn, NULL, error);
260 	g_free (real_dn);
261 	if (entries) {
262 		gint i;
263 		GSList *list = NULL;
264 		for (i = 0; entries [i]; i++) {
265 			GdaTreeNode* snode;
266 			GValue *dnv;
267 			GdaLdapEntry *lentry;
268 			lentry = entries [i];
269 			snode = gda_tree_manager_create_node (manager, node, lentry->dn);
270 
271 			/* full DN */
272 			g_value_set_string ((dnv = gda_value_new (G_TYPE_STRING)), lentry->dn);
273 			gda_tree_node_set_node_attribute (snode, "dn", dnv, NULL);
274 			gda_value_free (dnv);
275 
276 			/* RDN */
277                         gchar **array;
278                         array = gda_ldap_dn_split (lentry->dn, FALSE);
279                         if (array) {
280                                 g_value_set_string ((dnv = gda_value_new (G_TYPE_STRING)), array [0]);
281                                 gda_tree_node_set_node_attribute (snode, "rdn", dnv, NULL);
282 				gda_value_free (dnv);
283                                 g_strfreev (array);
284                         }
285 
286 			if (gda_tree_manager_get_managers (manager)) {
287 				g_value_set_boolean ((dnv = gda_value_new (G_TYPE_BOOLEAN)), TRUE);
288 				gda_tree_node_set_node_attribute (snode,
289 								  GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN,
290 								  dnv, NULL);
291 				gda_value_free (dnv);
292 			}
293 
294 			list = g_slist_prepend (list, snode);
295 			gda_ldap_entry_free (lentry);
296 		}
297 		g_free (entries);
298 
299 		if (node)
300 			gda_tree_node_set_node_attribute (node,
301 							  GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN,
302 							  NULL, NULL);
303 		return list;
304 	}
305 	else {
306 		if (out_error)
307 			*out_error = TRUE;
308 		return NULL;
309 	}
310 }
311