1 /*
2  * Copyright (C) 2011 - 2012 Vivien Malerba <malerba@gnome-db.org>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include <glib/gi18n-lib.h>
20 #include <libgda/libgda.h>
21 #include "mgr-ldap-classes.h"
22 #include "gda-tree-node.h"
23 #include <sqlite/virtual/gda-ldap-connection.h>
24 
25 struct _MgrLdapClassesPriv {
26 	BrowserConnection *bcnc;
27 	gchar *class;
28 	gboolean flat;
29 };
30 
31 static void mgr_ldap_classes_class_init (MgrLdapClassesClass *klass);
32 static void mgr_ldap_classes_init       (MgrLdapClasses *tmgr1, MgrLdapClassesClass *klass);
33 static void mgr_ldap_classes_dispose    (GObject *object);
34 
35 /* virtual methods */
36 static GSList *mgr_ldap_classes_update_children (GdaTreeManager *manager, GdaTreeNode *node,
37 						   const GSList *children_nodes,
38 						   gboolean *out_error, GError **error);
39 
40 static GObjectClass *parent_class = NULL;
41 
42 /*
43  * MgrLdapClasses class implementation
44  * @klass:
45  */
46 static void
mgr_ldap_classes_class_init(MgrLdapClassesClass * klass)47 mgr_ldap_classes_class_init (MgrLdapClassesClass *klass)
48 {
49 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
50 
51 	parent_class = g_type_class_peek_parent (klass);
52 
53 	/* virtual methods */
54 	((GdaTreeManagerClass*) klass)->update_children = mgr_ldap_classes_update_children;
55 
56 	object_class->dispose = mgr_ldap_classes_dispose;
57 }
58 
59 static void
mgr_ldap_classes_init(MgrLdapClasses * mgr,G_GNUC_UNUSED MgrLdapClassesClass * klass)60 mgr_ldap_classes_init (MgrLdapClasses *mgr, G_GNUC_UNUSED MgrLdapClassesClass *klass)
61 {
62 	g_return_if_fail (MGR_IS_LDAP_CLASSES (mgr));
63 	mgr->priv = g_new0 (MgrLdapClassesPriv, 1);
64 }
65 
66 static void
mgr_ldap_classes_dispose(GObject * object)67 mgr_ldap_classes_dispose (GObject *object)
68 {
69 	MgrLdapClasses *mgr = (MgrLdapClasses *) object;
70 
71 	g_return_if_fail (MGR_IS_LDAP_CLASSES (mgr));
72 
73 	if (mgr->priv) {
74 		if (mgr->priv->bcnc)
75 			g_object_unref (mgr->priv->bcnc);
76 		g_free (mgr->priv->class);
77 		g_free (mgr->priv);
78 		mgr->priv = NULL;
79 	}
80 
81 	/* chain to parent class */
82 	parent_class->dispose (object);
83 }
84 
85 /**
86  * mgr_ldap_classes_get_type:
87  *
88  * Returns: the GType
89  */
90 GType
mgr_ldap_classes_get_type(void)91 mgr_ldap_classes_get_type (void)
92 {
93         static GType type = 0;
94 
95         if (G_UNLIKELY (type == 0)) {
96                 static GMutex registering;
97                 static const GTypeInfo info = {
98                         sizeof (MgrLdapClassesClass),
99                         (GBaseInitFunc) NULL,
100                         (GBaseFinalizeFunc) NULL,
101                         (GClassInitFunc) mgr_ldap_classes_class_init,
102                         NULL,
103                         NULL,
104                         sizeof (MgrLdapClasses),
105                         0,
106                         (GInstanceInitFunc) mgr_ldap_classes_init,
107 			0
108                 };
109 
110                 g_mutex_lock (&registering);
111                 if (type == 0)
112                         type = g_type_register_static (GDA_TYPE_TREE_MANAGER, "_MgrLdapClasses", &info, 0);
113                 g_mutex_unlock (&registering);
114         }
115         return type;
116 }
117 
118 /*
119  * mgr_ldap_classes_new:
120  * @cnc: a #GdaConnection object
121  * @flat: %TRUE if listing all the classes, if %TRUE, then @classname is ignored.
122  * @classname: (allow-none): an LDAP class or %NULL for the "top" class
123  *
124  * Creates a new #GdaTreeManager object which will list the children classes
125  *
126  * Returns: (transfer full): a new #GdaTreeManager object
127  */
128 GdaTreeManager*
mgr_ldap_classes_new(BrowserConnection * bcnc,gboolean flat,const gchar * classname)129 mgr_ldap_classes_new (BrowserConnection *bcnc, gboolean flat, const gchar *classname)
130 {
131 	MgrLdapClasses *mgr;
132 	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
133 
134 	mgr = (MgrLdapClasses*) g_object_new (MGR_TYPE_LDAP_CLASSES, NULL);
135 
136 	mgr->priv->bcnc = g_object_ref (bcnc);
137 	mgr->priv->flat = flat;
138 	if (!flat) {
139 		if (classname)
140 			mgr->priv->class = g_strdup (classname);
141 	}
142 
143 	return (GdaTreeManager*) mgr;
144 }
145 
146 static GSList *
147 mgr_ldap_classes_update_children_flat (MgrLdapClasses *mgr, GdaTreeNode *node,
148 					 gboolean *out_error,
149 					 GError **error);
150 static GSList *
151 mgr_ldap_classes_update_children_nonflat (MgrLdapClasses *mgr, GdaTreeNode *node,
152 					    gboolean *out_error,
153 					    GError **error);
154 
155 static GSList *
mgr_ldap_classes_update_children(GdaTreeManager * manager,GdaTreeNode * node,G_GNUC_UNUSED const GSList * children_nodes,gboolean * out_error,GError ** error)156 mgr_ldap_classes_update_children (GdaTreeManager *manager, GdaTreeNode *node,
157 				    G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error,
158 				    GError **error)
159 {
160 	MgrLdapClasses *mgr = MGR_LDAP_CLASSES (manager);
161 
162 	if (mgr->priv->flat)
163 		return mgr_ldap_classes_update_children_flat (mgr, node, out_error, error);
164 	else
165 		return mgr_ldap_classes_update_children_nonflat (mgr, node, out_error, error);
166 
167 }
168 
169 static gint
class_sort_func(GdaLdapClass * lcl1,GdaLdapClass * lcl2)170 class_sort_func (GdaLdapClass *lcl1, GdaLdapClass *lcl2)
171 {
172 	if (lcl1->kind == lcl2->kind)
173 		return g_ascii_strcasecmp (lcl1->names[0], lcl2->names[0]);
174 	else
175 		return lcl1->kind - lcl2->kind;
176 }
177 
178 static GSList *
mgr_ldap_classes_update_children_nonflat(MgrLdapClasses * mgr,GdaTreeNode * node,gboolean * out_error,GError ** error)179 mgr_ldap_classes_update_children_nonflat (MgrLdapClasses *mgr, GdaTreeNode *node,
180 					    gboolean *out_error,
181 					    GError **error)
182 {
183 	gchar *real_class = NULL;
184 	if (!mgr->priv->bcnc) {
185 		g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR,
186 			     "%s", _("No LDAP connection specified"));
187 		if (out_error)
188 			*out_error = TRUE;
189 		goto onerror;
190 	}
191 
192 	const GValue *cvalue;
193 	cvalue = gda_tree_node_fetch_attribute (node, "kind");
194 	if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_BOOLEAN) && g_value_get_boolean (cvalue))
195 		return NULL;
196 
197 	if (node) {
198 		/* looking for a dn in @node's attributes */
199 		cvalue = gda_tree_node_fetch_attribute (node, "class");
200 		if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_STRING))
201 			real_class = g_value_dup_string (cvalue);
202 	}
203 	if (!real_class)
204 		real_class = g_strdup (mgr->priv->class);
205 
206 	GSList *classes_list;
207 	gboolean list_to_free = FALSE;
208 	if (real_class) {
209 		GdaLdapClass *lcl;
210 		lcl = browser_connection_get_class_info (mgr->priv->bcnc, real_class);
211 		if (!lcl)
212 			goto onerror;
213 		classes_list = (GSList*) lcl->children;
214 	}
215 	else {
216 		/* sort by kind */
217 		classes_list = g_slist_copy ((GSList*) browser_connection_get_top_classes (mgr->priv->bcnc));
218 		classes_list = g_slist_sort (classes_list, (GCompareFunc) class_sort_func);
219 		list_to_free = TRUE;
220 	}
221 
222 	GSList *list = NULL;
223 	const GSList *child;
224 	for (child = classes_list; child; child = child->next) {
225 		GdaLdapClass *sub;
226 		GdaTreeNode* snode;
227 		GValue *value;
228 		GdkPixbuf *pixbuf;
229 
230 		sub = (GdaLdapClass*) child->data;
231 
232 		snode = gda_tree_manager_create_node ((GdaTreeManager*) mgr, node, sub->names[0]);
233 
234 		/* class name */
235 		g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), sub->names[0]);
236 		gda_tree_node_set_node_attribute (snode, "class", value, NULL);
237 		gda_value_free (value);
238 
239 		/* icon */
240 		pixbuf = browser_get_pixbuf_for_ldap_class (sub->kind);
241 		value = gda_value_new (G_TYPE_OBJECT);
242 		g_value_set_object (value, pixbuf);
243 		gda_tree_node_set_node_attribute (snode, "icon", value, NULL);
244 		gda_value_free (value);
245 
246 		list = g_slist_prepend (list, snode);
247 	}
248 	if (list_to_free)
249 		g_slist_free (classes_list);
250 	return g_slist_reverse (list);
251 
252  onerror:
253 	g_free (real_class);
254 	if (out_error)
255 		*out_error = TRUE;
256 	return NULL;
257 }
258 
259 static void
classes_foreach_func(GdaLdapClass * lcl,GSList ** list)260 classes_foreach_func (GdaLdapClass *lcl, GSList **list)
261 {
262 	if (!g_slist_find (*list, lcl))
263 		*list = g_slist_insert_sorted (*list, lcl, (GCompareFunc) class_sort_func);
264 	g_slist_foreach (lcl->children, (GFunc) classes_foreach_func, list);
265 }
266 
267 static GSList *
mgr_ldap_classes_update_children_flat(MgrLdapClasses * mgr,GdaTreeNode * node,gboolean * out_error,GError ** error)268 mgr_ldap_classes_update_children_flat (MgrLdapClasses *mgr, GdaTreeNode *node,
269 					 gboolean *out_error,
270 					 GError **error)
271 {
272 	if (!mgr->priv->bcnc) {
273 		g_set_error (error, GDA_TREE_MANAGER_ERROR, GDA_TREE_MANAGER_UNKNOWN_ERROR,
274 			     "%s", _("No LDAP connection specified"));
275 		if (out_error)
276 			*out_error = TRUE;
277 		goto onerror;
278 	}
279 
280 	const GSList *top_classes_list;
281 	GSList *list = NULL, *classes_list = NULL;
282 	top_classes_list = browser_connection_get_top_classes (mgr->priv->bcnc);
283 	for (list = (GSList*) top_classes_list; list; list = list->next) {
284 		GdaLdapClass *lcl;
285 		lcl = (GdaLdapClass*) list->data;
286 		classes_list = g_slist_insert_sorted (classes_list, lcl, (GCompareFunc) class_sort_func);
287 		g_slist_foreach (lcl->children, (GFunc) classes_foreach_func, &classes_list);
288 	}
289 
290 	GSList *child;
291 	GdaLdapClassKind kind = 0;
292 	for (list = NULL, child = classes_list; child; child = child->next) {
293 		GdaLdapClass *sub;
294 		GdaTreeNode* snode;
295 		GValue *value;
296 		GdkPixbuf *pixbuf;
297 
298 		sub = (GdaLdapClass*) child->data;
299 
300 		if (kind != sub->kind) {
301 			/* add extra node as separator */
302 			const gchar *tmp;
303 			tmp = browser_get_kind_for_ldap_class (sub->kind);
304 			snode = gda_tree_manager_create_node ((GdaTreeManager*) mgr, node, tmp);
305 			list = g_slist_prepend (list, snode);
306 			kind = sub->kind;
307 
308 			/* marker */
309 			g_value_set_boolean ((value = gda_value_new (G_TYPE_BOOLEAN)), TRUE);
310 			gda_tree_node_set_node_attribute (snode, "kind", value, NULL);
311 			gda_value_free (value);
312 
313 			/* icon */
314 			pixbuf = browser_get_pixbuf_for_ldap_class (sub->kind);
315 			value = gda_value_new (G_TYPE_OBJECT);
316 			g_value_set_object (value, pixbuf);
317 			gda_tree_node_set_node_attribute (snode, "icon", value, NULL);
318 			gda_value_free (value);
319 		}
320 		snode = gda_tree_manager_create_node ((GdaTreeManager*) mgr, node, sub->names[0]);
321 
322 		/* class name */
323 		g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), sub->names[0]);
324 		gda_tree_node_set_node_attribute (snode, "class", value, NULL);
325 		gda_value_free (value);
326 
327 		/* icon */
328 		pixbuf = browser_get_pixbuf_for_ldap_class (sub->kind);
329 		value = gda_value_new (G_TYPE_OBJECT);
330 		g_value_set_object (value, pixbuf);
331 		gda_tree_node_set_node_attribute (snode, "icon", value, NULL);
332 		gda_value_free (value);
333 
334 		list = g_slist_prepend (list, snode);
335 	}
336 	g_slist_free (classes_list);
337 	return g_slist_reverse (list);
338 
339  onerror:
340 	if (out_error)
341 		*out_error = TRUE;
342 	return NULL;
343 }
344