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 #include <gtk/gtk.h>
20 #include <string.h>
21 #include <libgda-ui/libgda-ui.h>
main(int,char **)22 #include <libgda/libgda.h>
23 #include <libgda/virtual/gda-ldap-connection.h>
24 
25 gchar *host = NULL;
26 gchar *base = NULL;
27 gchar *user = NULL;
28 gchar *password = NULL;
29 gboolean usessl = FALSE;
30 
31 static GOptionEntry entries[] = {
32         { "server", 'h', 0, G_OPTION_ARG_STRING, &host, "Server", NULL},
33         { "basename", 'b', 0, G_OPTION_ARG_STRING, &base, "Base name", NULL},
34         { "user", 'u', 0, G_OPTION_ARG_STRING, &user, "User", NULL},
35         { "password", 'p', 0, G_OPTION_ARG_STRING, &password, "Password", NULL},
36         { "usessl", 's', 0, G_OPTION_ARG_NONE, &usessl, "Use SSL", NULL},
37         { NULL }
38 };
39 
40 
41 static GdaConnection *
42 open_ldap_connection ()
43 {
44 	GString *cncstring = NULL;
45 	gchar *enc;
46 	GdaConnection *cnc;
47 	GError *error = NULL;
48 
49 	if (host) {
50 		cncstring = g_string_new ("");
51 		enc = gda_rfc1738_encode (host);
52 		g_string_append_printf (cncstring, "HOST=%s", enc);
53 		g_free (enc);
54 	}
55 
56 	if (base) {
57 		if (cncstring)
58 			g_string_append_c (cncstring, ';');
59 		else
60 			cncstring = g_string_new ("");
61 		enc = gda_rfc1738_encode (base);
62 		g_string_append_printf (cncstring, "DB_NAME=%s", enc);
63 		g_free (enc);
64 	}
65 
66 	if (user) {
67 		if (cncstring)
68 			g_string_append_c (cncstring, ';');
69 		else
70 			cncstring = g_string_new ("");
71 		enc = gda_rfc1738_encode (user);
72 		g_string_append_printf (cncstring, "USERNAME=%s", enc);
73 		g_free (enc);
74 	}
75 
76 	if (password) {
77 		if (cncstring)
78 			g_string_append_c (cncstring, ';');
79 		else
80 			cncstring = g_string_new ("");
81 		enc = gda_rfc1738_encode (password);
82 		g_string_append_printf (cncstring, "PASSWORD=%s", enc);
83 		g_free (enc);
84 	}
85 
86 	if (usessl) {
87 		if (cncstring)
88 			g_string_append_c (cncstring, ';');
89 		else
90 			cncstring = g_string_new ("");
91 		g_string_append (cncstring, "USER_SSL=TRUE");
92 	}
93 
94 	if (! cncstring) {
95 		g_print ("No connection specified!\n");
96 		exit (1);
97 	}
98 
99 	g_print ("Using connection string: %s\n", cncstring->str);
100         cnc = gda_connection_open_from_string ("Ldap", cncstring->str,
101                                                NULL,
102                                                GDA_CONNECTION_OPTIONS_NONE, &error);
103         if (!cnc) {
104                 g_print ("Error opening connection (cncstring=[%s]): %s\n",
105                          cncstring->str,
106                          error && error->message ? error->message : "No detail");
107                 exit (1);
108         }
109         g_string_free (cncstring, TRUE);
110 
111 	return cnc;
112 }
113 
114 typedef struct {
115 	GtkTreeView *tview;
116 	GdauiTreeStore *store;
117 	GdaTree *tree;
118 	GdaTreeNode *node;
119 } IdleData;
120 
121 static void
122 idle_data_free (IdleData *data)
123 {
124 	g_object_unref (data->tview);
125 	g_object_unref (data->store);
126 	g_object_unref (data->tree);
127 	g_object_unref (data->node);
128 	g_free (data);
129 }
130 
131 static gboolean ldap_update_tree_part (IdleData *data);
132 static gboolean
133 test_expand_row_cb (GtkTreeView *tree_view, GtkTreeIter *iter,
134                     G_GNUC_UNUSED GtkTreePath *path, GdaTree *tree)
135 {
136         GdaTreeNode *node;
137 	GtkTreeModel *store;
138 
139 	store = gtk_tree_view_get_model (tree_view);
140         node = gdaui_tree_store_get_node (GDAUI_TREE_STORE (store), iter);
141         if (gda_tree_node_get_child_index (node, 0))
142                 return FALSE;
143 
144 	const GValue *cv;
145 	cv = gda_tree_node_get_node_attribute (node,
146 					       GDA_ATTRIBUTE_TREE_NODE_UNKNOWN_CHILDREN);
147 	if (cv && (G_VALUE_TYPE (cv) == G_TYPE_BOOLEAN) &&
148 	    g_value_get_boolean (cv)) {
149 		IdleData *data;
150 		data = g_new (IdleData, 1);
151 		data->tview = g_object_ref (G_OBJECT (tree_view));
152 		data->store = g_object_ref (G_OBJECT (store));
153 		data->tree = g_object_ref (G_OBJECT (tree));
154 		data->node = g_object_ref (G_OBJECT (node));
155 
156 		g_idle_add_full (G_PRIORITY_HIGH_IDLE, (GSourceFunc) ldap_update_tree_part,
157 				 data, (GDestroyNotify) idle_data_free);
158 	}
159 	return TRUE;
160 }
161 
162 static gboolean
163 ldap_update_tree_part (IdleData *data)
164 {
165         gda_tree_update_children (data->tree, data->node, NULL);
166 
167 	GtkTreeIter iter;
168 	if (gdaui_tree_store_get_iter (data->store, &iter, data->node) &&
169 	    gda_tree_node_get_child_index (data->node, 0)) {
170 		GtkTreePath *path;
171 		path = gtk_tree_model_get_path (GTK_TREE_MODEL (data->store), &iter);
172 		g_signal_handlers_block_by_func (data->tview,
173 						 G_CALLBACK (test_expand_row_cb), data->tree);
174 		gtk_tree_view_expand_row (data->tview, path, FALSE);
175 		g_signal_handlers_unblock_by_func (data->tview,
176 						   G_CALLBACK (test_expand_row_cb), data->tree);
177 		gtk_tree_path_free (path);
178 	}
179 
180 	return FALSE;
181 }
182 
183 static void
184 selection_changed_cb (GtkTreeSelection *sel, GdauiTreeStore *store)
185 {
186 	GtkTreeIter iter;
187 	if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
188 		gchar *rdn;
189 		gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &rdn, -1);
190 		g_print ("Selected RDN: %s\n", rdn);
191 		g_free (rdn);
192 
193 		GdaTreeNode *node;
194 		const GValue *cvalue;
195 		node = gdaui_tree_store_get_node (store, &iter);
196 		g_assert (node);
197 		cvalue = gda_tree_node_get_node_attribute (node, "dn");
198 		g_assert (cvalue);
199 		g_print ("         DN:  %s\n", g_value_get_string (cvalue));
200 	}
201 }
202 
203 static GtkWidget *
204 create_window (GdaConnection *cnc)
205 {
206 	GtkWidget *win = NULL;
207 
208 	/* Window */
209 	win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
210 	gtk_window_set_title  (GTK_WINDOW (win), "LDAP Browser");
211 	gtk_window_set_default_size (GTK_WINDOW (win), 640, 480);
212 	gtk_container_set_border_width (GTK_CONTAINER (win), 5);
213 	gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_CENTER);
214 	g_signal_connect (G_OBJECT (win), "destroy", gtk_main_quit, NULL);
215 
216 	/* container */
217 	GtkWidget *vb, *hp;
218 	vb = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
219 	gtk_container_add (GTK_CONTAINER (win), vb);
220 	hp = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
221         gtk_box_pack_start (GTK_BOX (vb), hp, TRUE, TRUE, 0);
222 
223 	GdaTree *tree;
224 	GdaTreeManager *mgr;
225 	GtkTreeModel *store;
226 	GtkWidget *tview, *sw;
227 	GtkCellRenderer *renderer;
228 	GtkTreeViewColumn *column;
229 
230 	tree = gda_tree_new ();
231 	mgr = gda_tree_mgr_ldap_new (cnc, NULL);
232 	gda_tree_add_manager (tree, mgr);
233 	gda_tree_manager_add_manager (mgr, mgr);
234 	g_object_unref (mgr);
235 
236 	gda_tree_update_children (tree, NULL, NULL);
237 
238 	store = gdaui_tree_store_new (tree, 1, G_TYPE_STRING, "rdn");
239 	g_object_unref (tree);
240 	tview = gtk_tree_view_new_with_model (store);
241 	g_signal_connect (tview, "test-expand-row",
242                           G_CALLBACK (test_expand_row_cb), tree);
243 
244 	renderer = gtk_cell_renderer_text_new ();
245         column = gtk_tree_view_column_new_with_attributes ("DN", renderer, "text", 0, NULL);
246         gtk_tree_view_append_column (GTK_TREE_VIEW (tview), column);
247         gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tview), column);
248 
249 	sw = gtk_scrolled_window_new (NULL, NULL);
250         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC,
251                                         GTK_POLICY_AUTOMATIC);
252         gtk_container_add (GTK_CONTAINER (sw), tview);
253         gtk_paned_add1 (GTK_PANED (hp), sw);
254 
255 	/* selection */
256 	GtkTreeSelection *sel;
257 	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tview));
258 	gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
259 	g_signal_connect (sel, "changed",
260 			  G_CALLBACK (selection_changed_cb), store);
261 
262 	gtk_widget_show_all (vb);
263 
264 	return win;
265 }
266 
267 /*
268  * Entree du programme:
269  */
270 int main (int argc, char ** argv)
271 {
272 	GdaConnection *cnc;
273 	GOptionContext *context;
274 	GError *error = NULL;
275 
276 	context = g_option_context_new (NULL);
277         g_option_context_add_main_entries (context, entries, NULL);
278         if (!g_option_context_parse (context, &argc, &argv, &error)) {
279                 g_print ("Can't parse arguments: %s", error->message);
280                 exit (1);
281         }
282         g_option_context_free (context);
283 
284 	gtk_init (& argc, & argv);
285 	gdaui_init ();
286 
287 	cnc = open_ldap_connection ();
288 	gtk_widget_show (create_window (cnc));
289 	gtk_main ();
290 
291 	g_object_unref (cnc);
292 
293 	return 0;
294 }
295