Update the tree.c GTK+ App so it can walk down directories etc ...
[kai/samba.git] / source3 / client / tree.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0
4    SMB client GTK+ tree-based application
5    Copyright (C) Andrew Tridgell 1998
6    Copyright (C) Richard Sharpe 2001
7    Copyright (C) John Terpstra 2001
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /* example-gtk+ application, ripped off from the gtk+ tree.c sample */
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <gtk/gtk.h>
29 #include "libsmbclient.h"
30
31 struct tree_data {
32
33   guint32 type;    /* Type of tree item, an SMBC_TYPE */
34   char name[256];  /* May need to change this later   */
35
36 };
37
38 /*
39  * We are given a widget, and we want to retrieve its URL so we 
40  * can do a directory listing.
41  *
42  * We walk back up the tree, picking up pieces until we hit a server or
43  * workgroup type and return a path from there
44  */
45
46 static char path_string[1024];
47
48 char *get_path(GtkWidget *item)
49 {
50   GtkWidget *p = item;
51   struct tree_data *pd;
52   char *comps[1024];  /* We keep pointers to the components here */
53   int i = 0, j, level,type;
54
55   /* Walk back up the tree, getting the private data */
56
57   level = GTK_TREE(item->parent)->level;
58
59   /* Pick up this item's component info */
60
61   pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(item));
62
63   comps[i++] = pd->name;
64   type = pd->type;
65
66   while (level > 0 && type != SMBC_SERVER && type != SMBC_WORKGROUP) {
67
68     /* Find the parent and extract the data etc ... */
69
70     p = GTK_WIDGET(p->parent);    
71     p = GTK_WIDGET(GTK_TREE(p)->tree_owner);
72
73     pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(p));
74
75     level = GTK_TREE(item->parent)->level;
76
77     comps[i++] = pd->name;
78     type = pd->type;
79
80   }
81
82   /* 
83    * Got a list of comps now, should check that we did not hit a workgroup
84    * when we got other things as well ... Later
85    *
86    * Now, build the path
87    */
88
89   snprintf(path_string, sizeof(path_string), "smb:/");
90
91   for (j = i - 1; j >= 0; j--) {
92
93     strncat(path_string, "/", sizeof(path_string) - strlen(path_string));
94     strncat(path_string, comps[j], sizeof(path_string) - strlen(path_string));
95
96   }
97   
98   fprintf(stdout, "Path string = %s\n", path_string);
99
100   return path_string;
101
102 }
103
104 struct tree_data *make_tree_data(guint32 type, const char *name)
105 {
106   struct tree_data *p = (struct tree_data *)malloc(sizeof(struct tree_data));
107
108   if (p) {
109
110     p->type = type;
111     strncpy(p->name, name, sizeof(p->name));
112
113   }
114
115   return p;
116
117 }
118
119 /* for all the GtkItem:: and GtkTreeItem:: signals */
120 static void cb_itemsignal( GtkWidget *item,
121                            gchar     *signame )
122 {
123   GtkWidget *real_tree, *aitem, *subtree;
124   gchar *name;
125   GtkLabel *label;
126   gint dh, err, dirlen, level;
127   char dirbuf[512];
128   struct smbc_dirent *dirp;
129   
130   label = GTK_LABEL (GTK_BIN (item)->child);
131   /* Get the text of the label */
132   gtk_label_get (label, &name);
133
134   level = GTK_TREE(item->parent)->level;
135
136   /* Get the level of the tree which the item is in */
137   g_print ("%s called for item %s->%p, level %d\n", signame, name,
138            item, GTK_TREE (item->parent)->level);
139
140   if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
141     char server[128];
142
143     if ((dh = smbc_opendir(get_path(item))) < 0) { /* Handle error */
144
145       g_print("cb_wholenet: Could not open dir %s, %s\n", server, 
146               strerror(errno));
147
148       gtk_main_quit();
149
150       return;
151
152     }
153
154     real_tree = GTK_TREE_ITEM_SUBTREE(item);  /* Get the subtree */
155
156     while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, 
157                                 sizeof(dirbuf))) != 0) {
158
159       if (err < 0) { /* An error, report it */
160
161         g_print("cb_wholenet: Could not read dir smbc://, %s\n",
162                 strerror(errno));
163
164         gtk_main_quit();
165
166         return;
167
168       }
169
170       dirp = (struct smbc_dirent *)dirbuf;
171
172       while (err > 0) {
173         struct tree_data *my_data;
174
175         dirlen = dirp->dirlen;
176
177         my_data = make_tree_data(dirp->smbc_type, dirp->name);
178
179         if (!my_data) {
180
181           g_print("Could not allocate space for tree_data: %s\n",
182                   dirp->name);
183
184           gtk_main_quit();
185           return;
186
187         }
188
189         aitem = gtk_tree_item_new_with_label(dirp->name);
190
191         /* Connect all GtkItem:: and GtkTreeItem:: signals */
192         gtk_signal_connect (GTK_OBJECT(aitem), "select",
193                             GTK_SIGNAL_FUNC(cb_itemsignal), "select");
194         gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
195                             GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
196         gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
197                             GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
198         gtk_signal_connect (GTK_OBJECT(aitem), "expand",
199                             GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
200         gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
201                             GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
202         /* Add it to the parent tree */
203         gtk_tree_append (GTK_TREE(real_tree), aitem);
204
205         gtk_widget_show (aitem);
206
207         gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
208
209         fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
210
211         if (dirp->smbc_type != SMBC_FILE && dirp->smbc_type != SMBC_IPC_SHARE){
212           
213           subtree = gtk_tree_new();
214           gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
215
216         }
217
218         (char *)dirp += dirlen;
219         err -= dirlen;
220
221       }
222
223     }
224
225     smbc_closedir(dh);   
226
227   }
228
229 }
230
231 /* Note that this is never called */
232 static void cb_unselect_child( GtkWidget *root_tree,
233                                GtkWidget *child,
234                                GtkWidget *subtree )
235 {
236   g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
237            root_tree, subtree, child);
238 }
239
240 /* Note that this is called every time the user clicks on an item,
241    whether it is already selected or not. */
242 static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
243                              GtkWidget *subtree)
244 {
245   g_print ("select_child called for root tree %p, subtree %p, child %p\n",
246            root_tree, subtree, child);
247 }
248
249 static void cb_selection_changed( GtkWidget *tree )
250 {
251   GList *i;
252   
253   g_print ("selection_change called for tree %p\n", tree);
254   g_print ("selected objects are:\n");
255
256   i = GTK_TREE_SELECTION(tree);
257   while (i){
258     gchar *name;
259     GtkLabel *label;
260     GtkWidget *item;
261
262     /* Get a GtkWidget pointer from the list node */
263     item = GTK_WIDGET (i->data);
264     label = GTK_LABEL (GTK_BIN (item)->child);
265     gtk_label_get (label, &name);
266     g_print ("\t%s on level %d\n", name, GTK_TREE
267              (item->parent)->level);
268     i = i->next;
269   }
270 }
271
272 /*
273  * Expand or collapse the whole network ...
274  */
275 static void cb_wholenet(GtkWidget *item, gchar *signame)
276 {
277   GtkWidget *real_tree, *aitem, *subtree;
278   gchar *name;
279   GtkLabel *label;
280   gint dh, err, dirlen;
281   char dirbuf[512];
282   struct smbc_dirent *dirp;
283   
284   label = GTK_LABEL (GTK_BIN (item)->child);
285   gtk_label_get (label, &name);
286   g_print ("%s called for item %s->%p, level %d\n", signame, name,
287            item, GTK_TREE (item->parent)->level);
288
289   if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
290
291     if ((dh = smbc_opendir("smb://")) < 0) { /* Handle error */
292
293       g_print("cb_wholenet: Could not open dir smbc://, %s\n",
294               strerror(errno));
295
296       gtk_main_quit();
297
298       return;
299
300     }
301
302     real_tree = GTK_TREE_ITEM_SUBTREE(item);  /* Get the subtree */
303
304     while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, 
305                                 sizeof(dirbuf))) != 0) {
306
307       if (err < 0) { /* An error, report it */
308
309         g_print("cb_wholenet: Could not read dir smbc://, %s\n",
310                 strerror(errno));
311
312         gtk_main_quit();
313
314         return;
315
316       }
317
318       dirp = (struct smbc_dirent *)dirbuf;
319
320       while (err > 0) {
321         struct tree_data *my_data;
322
323         dirlen = dirp->dirlen;
324
325         my_data = make_tree_data(dirp->smbc_type, dirp->name);
326
327         aitem = gtk_tree_item_new_with_label(dirp->name);
328
329         /* Connect all GtkItem:: and GtkTreeItem:: signals */
330         gtk_signal_connect (GTK_OBJECT(aitem), "select",
331                             GTK_SIGNAL_FUNC(cb_itemsignal), "select");
332         gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
333                             GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
334         gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
335                             GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
336         gtk_signal_connect (GTK_OBJECT(aitem), "expand",
337                             GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
338         gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
339                             GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
340
341         gtk_tree_append (GTK_TREE(real_tree), aitem);
342         /* Show it - this can be done at any time */
343         gtk_widget_show (aitem);
344
345         gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
346
347         fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
348
349         subtree = gtk_tree_new();
350
351         gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
352
353         (char *)dirp += dirlen;
354         err -= dirlen;
355
356       }
357
358     }
359
360     smbc_closedir(dh);   
361
362   }
363
364 }
365
366 static void 
367 auth_fn(char *server, char *share,
368              char **workgroup, char **username, char **password)
369 {
370
371   *workgroup = "";
372   *username = "test";
373   *password = "test";
374
375 }
376
377 int main( int   argc,
378           char *argv[] )
379 {
380   GtkWidget *window, *scrolled_win, *tree;
381   GtkWidget *subtree, *item;
382   gint err, dh;
383   gint i;
384   char dirbuf[512];
385   struct smbc_dirent *dirp;
386
387   gtk_init (&argc, &argv);
388
389   /* Init the smbclient library */
390
391   err = smbc_init(auth_fn, "", 10);
392
393   /* a generic toplevel window */
394   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
395   gtk_signal_connect (GTK_OBJECT(window), "delete_event",
396                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
397   gtk_container_set_border_width (GTK_CONTAINER(window), 5);
398
399   /* A generic scrolled window */
400   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
401   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
402                                   GTK_POLICY_AUTOMATIC,
403                                   GTK_POLICY_AUTOMATIC);
404   gtk_widget_set_usize (scrolled_win, 150, 200);
405   gtk_container_add (GTK_CONTAINER(window), scrolled_win);
406   gtk_widget_show (scrolled_win);
407   
408   /* Create the root tree */
409   tree = gtk_tree_new();
410   g_print ("root tree is %p\n", tree);
411   /* connect all GtkTree:: signals */
412   gtk_signal_connect (GTK_OBJECT(tree), "select_child",
413                       GTK_SIGNAL_FUNC(cb_select_child), tree);
414   gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
415                       GTK_SIGNAL_FUNC(cb_unselect_child), tree);
416   gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
417                       GTK_SIGNAL_FUNC(cb_selection_changed), tree);
418   /* Add it to the scrolled window */
419   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
420                                          tree);
421   /* Set the selection mode */
422   gtk_tree_set_selection_mode (GTK_TREE(tree),
423                                GTK_SELECTION_MULTIPLE);
424   /* Show it */
425   gtk_widget_show (tree);
426
427   /* Now, build the top level display ... */
428
429   if ((dh = smbc_opendir("smb:///")) < 0) {
430
431     fprintf(stderr, "Could not list default workgroup: smb:///: %s\n",
432             strerror(errno));
433
434     exit(1);
435
436   }
437
438   /* Create a tree item for Whole Network */
439
440   item = gtk_tree_item_new_with_label ("Whole Network");
441   /* Connect all GtkItem:: and GtkTreeItem:: signals */
442   gtk_signal_connect (GTK_OBJECT(item), "select",
443                       GTK_SIGNAL_FUNC(cb_itemsignal), "select");
444   gtk_signal_connect (GTK_OBJECT(item), "deselect",
445                       GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
446   gtk_signal_connect (GTK_OBJECT(item), "toggle",
447                       GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
448   gtk_signal_connect (GTK_OBJECT(item), "expand",
449                       GTK_SIGNAL_FUNC(cb_wholenet), "expand");
450   gtk_signal_connect (GTK_OBJECT(item), "collapse",
451                       GTK_SIGNAL_FUNC(cb_wholenet), "collapse");
452   /* Add it to the parent tree */
453   gtk_tree_append (GTK_TREE(tree), item);
454   /* Show it - this can be done at any time */
455   gtk_widget_show (item);
456
457   subtree = gtk_tree_new();  /* A subtree for Whole Network */
458
459   gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
460
461   /* Now, get the items in smb:/// and add them to the tree */
462
463   dirp = (struct smbc_dirent *)dirbuf;
464
465   while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, 
466                               sizeof(dirbuf))) != 0) {
467
468     if (err < 0) { /* Handle the error */
469
470       fprintf(stderr, "Could not read directory for smbc:///: %s\n",
471               strerror(errno));
472
473       exit(1);
474
475     }
476
477     fprintf(stdout, "Dir len: %u\n", err);
478
479     while (err > 0) { /* Extract each entry and make a sub-tree */
480       struct tree_data *my_data;
481       int dirlen = dirp->dirlen;
482
483       my_data = make_tree_data(dirp->smbc_type, dirp->name);
484
485       item = gtk_tree_item_new_with_label(dirp->name);
486       /* Connect all GtkItem:: and GtkTreeItem:: signals */
487       gtk_signal_connect (GTK_OBJECT(item), "select",
488                           GTK_SIGNAL_FUNC(cb_itemsignal), "select");
489       gtk_signal_connect (GTK_OBJECT(item), "deselect",
490                           GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
491       gtk_signal_connect (GTK_OBJECT(item), "toggle",
492                           GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
493       gtk_signal_connect (GTK_OBJECT(item), "expand",
494                           GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
495       gtk_signal_connect (GTK_OBJECT(item), "collapse",
496                           GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
497       /* Add it to the parent tree */
498       gtk_tree_append (GTK_TREE(tree), item);
499       /* Show it - this can be done at any time */
500       gtk_widget_show (item);
501
502       gtk_object_set_user_data(GTK_OBJECT(item), (gpointer)my_data);
503
504       fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
505
506       subtree = gtk_tree_new();
507
508       gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
509
510       (char *)dirp += dirlen;
511       err -= dirlen;
512
513     }
514
515   }
516
517   smbc_closedir(dh); /* FIXME, check for error :-) */
518
519   /* Show the window and loop endlessly */
520   gtk_widget_show (window);
521   gtk_main();
522   return 0;
523 }
524 /* example-end */