1 /*
2 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
3 * Copyright (C) 2011 Vivien Malerba <malerba@gnome-db.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include <glib/gi18n-lib.h>
21 #include <libgda/libgda.h>
22 #include "mgr-ldap-entries.h"
23 #include <libgda/gda-tree-node.h>
24
25 struct _MgrLdapEntriesPriv {
26 BrowserConnection *bcnc;
27 gchar *dn;
28 };
29
30 static void mgr_ldap_entries_class_init (MgrLdapEntriesClass *klass);
31 static void mgr_ldap_entries_init (MgrLdapEntries *tmgr1, MgrLdapEntriesClass *klass);
32 static void mgr_ldap_entries_dispose (GObject *object);
33
34 /* virtual methods */
35 static GSList *mgr_ldap_entries_update_children (GdaTreeManager *manager, GdaTreeNode *node,
36 const GSList *children_nodes,
37 gboolean *out_error, GError **error);
38
39 static GObjectClass *parent_class = NULL;
40
41 /*
42 * MgrLdapEntries class implementation
43 * @klass:
44 */
45 static void
mgr_ldap_entries_class_init(MgrLdapEntriesClass * klass)46 mgr_ldap_entries_class_init (MgrLdapEntriesClass *klass)
47 {
48 GObjectClass *object_class = G_OBJECT_CLASS (klass);
49
50 parent_class = g_type_class_peek_parent (klass);
51
52 /* virtual methods */
53 ((GdaTreeManagerClass*) klass)->update_children = mgr_ldap_entries_update_children;
54
55 /* Properties */
56 object_class->dispose = mgr_ldap_entries_dispose;
57 }
58
59 static void
mgr_ldap_entries_init(MgrLdapEntries * mgr,G_GNUC_UNUSED MgrLdapEntriesClass * klass)60 mgr_ldap_entries_init (MgrLdapEntries *mgr, G_GNUC_UNUSED MgrLdapEntriesClass *klass)
61 {
62 g_return_if_fail (MGR_IS_LDAP_ENTRIES (mgr));
63 mgr->priv = g_new0 (MgrLdapEntriesPriv, 1);
64 }
65
66 static void
mgr_ldap_entries_dispose(GObject * object)67 mgr_ldap_entries_dispose (GObject *object)
68 {
69 MgrLdapEntries *mgr = (MgrLdapEntries *) object;
70
71 g_return_if_fail (MGR_IS_LDAP_ENTRIES (mgr));
72
73 if (mgr->priv) {
74 if (mgr->priv->bcnc)
75 g_object_unref (mgr->priv->bcnc);
76 g_free (mgr->priv->dn);
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 * browser_tree_mgr_select_get_type:
87 *
88 * Returns: the GType
89 */
90 GType
mgr_ldap_entries_get_type(void)91 mgr_ldap_entries_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 (MgrLdapEntriesClass),
99 (GBaseInitFunc) NULL,
100 (GBaseFinalizeFunc) NULL,
101 (GClassInitFunc) mgr_ldap_entries_class_init,
102 NULL,
103 NULL,
104 sizeof (MgrLdapEntries),
105 0,
106 (GInstanceInitFunc) mgr_ldap_entries_init,
107 0
108 };
109
110 g_mutex_lock (®istering);
111 if (type == 0)
112 type = g_type_register_static (GDA_TYPE_TREE_MANAGER, "MgrLdapEntries", &info, 0);
113 g_mutex_unlock (®istering);
114 }
115 return type;
116 }
117
118 /**
119 * mgr_ldap_entries_new:
120 * @cnc: a #BrowserConnection object
121 * @dn: (allow-none): a schema name or %NULL
122 *
123 * Creates a new #BrowserTreeManager object which will list the children of the LDAP entry which Distinguished name
124 * is @dn. If @dn is %NULL, then the tree manager will look in the tree itself for an attribute named "dn" and
125 * use it.
126 *
127 * Returns: (transfer full): a new #BrowserTreeManager object
128 */
129 GdaTreeManager*
mgr_ldap_entries_new(BrowserConnection * bcnc,const gchar * dn)130 mgr_ldap_entries_new (BrowserConnection *bcnc, const gchar *dn)
131 {
132 MgrLdapEntries *mgr;
133 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
134
135 mgr = (MgrLdapEntries*) g_object_new (MGR_TYPE_LDAP_ENTRIES, NULL);
136
137 mgr->priv->bcnc = g_object_ref (bcnc);
138 if (dn)
139 mgr->priv->dn = g_strdup (dn);
140
141 return (GdaTreeManager*) mgr;
142 }
143
144 typedef struct {
145 GMainLoop *loop;
146 GdaLdapEntry **entries;
147 GError *error;
148 } AsyncExecData;
149
150 static void
update_children_cb(G_GNUC_UNUSED BrowserConnection * bcnc,gpointer out_result,AsyncExecData * data,GError * error)151 update_children_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
152 gpointer out_result, AsyncExecData *data, GError *error)
153 {
154 data->entries = (GdaLdapEntry **) out_result;
155 if (! data->entries && error)
156 data->error = g_error_copy (error);
157 g_main_loop_quit (data->loop);
158 }
159
160 static gint
lentry_array_sort_func(gconstpointer a,gconstpointer b)161 lentry_array_sort_func (gconstpointer a, gconstpointer b)
162 {
163 GdaLdapEntry *e1, *e2;
164 e1 = *((GdaLdapEntry**) a);
165 e2 = *((GdaLdapEntry**) b);
166 GdaLdapAttribute *cna1, *cna2;
167 const gchar *str1 = NULL, *str2 = NULL;
168
169 cna1 = g_hash_table_lookup (e1->attributes_hash, "cn");
170 cna2 = g_hash_table_lookup (e2->attributes_hash, "cn");
171 if (cna1 && (cna1->nb_values > 0) && (G_VALUE_TYPE (cna1->values[0]) == G_TYPE_STRING))
172 str1 = g_value_get_string (cna1->values[0]);
173 else
174 str1 = e1->dn ? e1->dn : "";
175 if (cna2 && (cna2->nb_values > 0) && (G_VALUE_TYPE (cna2->values[0]) == G_TYPE_STRING))
176 str2 = g_value_get_string (cna2->values[0]);
177 else
178 str2 = e2->dn ? e2->dn : "";
179
180 return strcmp (str2, str1);
181 }
182
183 static GSList *
mgr_ldap_entries_update_children(GdaTreeManager * manager,GdaTreeNode * node,G_GNUC_UNUSED const GSList * children_nodes,gboolean * out_error,GError ** error)184 mgr_ldap_entries_update_children (GdaTreeManager *manager, GdaTreeNode *node,
185 G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error,
186 GError **error)
187 {
188 MgrLdapEntries *mgr = MGR_LDAP_ENTRIES (manager);
189 gchar *real_dn = NULL;
190
191 g_return_val_if_fail (mgr->priv->bcnc, NULL);
192
193 if (mgr->priv->dn)
194 real_dn = g_strdup (mgr->priv->dn);
195 else if (node) {
196 /* looking for a dn in @node's attributes */
197 const GValue *cvalue;
198 cvalue = gda_tree_node_fetch_attribute (node, "dn");
199 if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_STRING))
200 real_dn = g_value_dup_string (cvalue);
201 }
202
203 AsyncExecData data;
204 guint id;
205 data.loop = NULL;
206 data.entries = NULL;
207 data.error = NULL;
208 gchar *attrs[] = {"objectClass", "cn", NULL};
209
210 id = browser_connection_ldap_get_entry_children (mgr->priv->bcnc, real_dn, attrs,
211 BROWSER_CONNECTION_JOB_CALLBACK (update_children_cb),
212 &data, error);
213 g_free (real_dn);
214 if (id == 0) {
215 if (out_error)
216 *out_error = TRUE;
217 return NULL;
218 }
219 data.loop = g_main_loop_new (NULL, FALSE);
220 g_main_loop_run (data.loop);
221 g_main_loop_unref (data.loop);
222
223 if (data.entries) {
224 guint i;
225 GSList *list = NULL;
226 GArray *sorted_array;
227 sorted_array = g_array_new (FALSE, FALSE, sizeof (GdaLdapEntry*));
228 for (i = 0; data.entries [i]; i++) {
229 GdaLdapEntry *lentry;
230 lentry = data.entries [i];
231 g_array_prepend_val (sorted_array, lentry);
232 }
233 g_free (data.entries);
234
235 g_array_sort (sorted_array, (GCompareFunc) lentry_array_sort_func);
236
237 for (i = 0; i < sorted_array->len; i++) {
238 GdaTreeNode* snode;
239 GValue *dnv;
240 GdaLdapEntry *lentry;
241
242 lentry = g_array_index (sorted_array, GdaLdapEntry*, i);
243 snode = gda_tree_manager_create_node (manager, node, lentry->dn);
244
245 /* full DN */
246 g_value_set_string ((dnv = gda_value_new (G_TYPE_STRING)), lentry->dn);
247 gda_tree_node_set_node_attribute (snode, "dn", dnv, NULL);
248 gda_value_free (dnv);
249
250 /* RDN */
251 gchar **array;
252 array = gda_ldap_dn_split (lentry->dn, FALSE);
253 if (array) {
254 g_value_set_string ((dnv = gda_value_new (G_TYPE_STRING)), array [0]);
255 gda_tree_node_set_node_attribute (snode, "rdn", dnv, NULL);
256 gda_value_free (dnv);
257 g_strfreev (array);
258 }
259
260 /* CN */
261 GdaLdapAttribute *attr;
262 attr = g_hash_table_lookup (lentry->attributes_hash, "cn");
263 if (attr && (attr->nb_values >= 1)) {
264 const GValue *cvalue;
265 cvalue = attr->values [0];
266 if (cvalue && (G_VALUE_TYPE (cvalue) == G_TYPE_STRING))
267 gda_tree_node_set_node_attribute (snode, "cn", cvalue, NULL);
268 }
269
270 /* icon */
271 GdkPixbuf *pixbuf;
272 attr = g_hash_table_lookup (lentry->attributes_hash, "objectClass");
273 pixbuf = browser_connection_ldap_icon_for_class (attr);
274
275 dnv = gda_value_new (G_TYPE_OBJECT);
276 g_value_set_object (dnv, pixbuf);
277 gda_tree_node_set_node_attribute (snode, "icon", dnv, NULL);
278 gda_value_free (dnv);
279
280 if (gda_tree_manager_get_managers (manager)) {
281 g_value_set_boolean ((dnv = gda_value_new (G_TYPE_BOOLEAN)), TRUE);
282 gda_tree_node_set_node_attribute (snode,
283 GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN,
284 dnv, NULL);
285 gda_value_free (dnv);
286 }
287
288 list = g_slist_prepend (list, snode);
289 gda_ldap_entry_free (lentry);
290 }
291 g_array_free (sorted_array, TRUE);
292
293 if (node)
294 gda_tree_node_set_node_attribute (node,
295 GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN,
296 NULL, NULL);
297
298 return list;
299 }
300 else {
301 g_propagate_error (error, data.error);
302 if (out_error)
303 *out_error = TRUE;
304 return NULL;
305 }
306 }
307