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 3 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, see <http://www.gnu.org/licenses/>. 21*/ 22 23/* example-gtk+ application, ripped off from the gtk+ tree.c sample */ 24 25#include <stdio.h> 26#include <errno.h> 27#include <string.h> 28#include <stdlib.h> 29#include <gtk/gtk.h> 30#include "libsmbclient.h" 31 32static GtkWidget *clist; 33 34struct tree_data { 35 36 guint32 type; /* Type of tree item, an SMBC_TYPE */ 37 char name[256]; /* May need to change this later */ 38 39}; 40 41void error_message(gchar *message) { 42 43 GtkWidget *dialog, *label, *okay_button; 44 45 /* Create the widgets */ 46 47 dialog = gtk_dialog_new(); 48 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); 49 label = gtk_label_new (message); 50 okay_button = gtk_button_new_with_label("Okay"); 51 52 /* Ensure that the dialog box is destroyed when the user clicks ok. */ 53 54 gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked", 55 GTK_SIGNAL_FUNC (gtk_widget_destroy), 56 GTK_OBJECT(dialog)); 57 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), 58 okay_button); 59 60 /* Add the label, and show everything we've added to the dialog. */ 61 62 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), 63 label); 64 gtk_widget_show_all (dialog); 65} 66 67/* 68 * We are given a widget, and we want to retrieve its URL so we 69 * can do a directory listing. 70 * 71 * We walk back up the tree, picking up pieces until we hit a server or 72 * workgroup type and return a path from there 73 */ 74 75static char path_string[1024]; 76 77char *get_path(GtkWidget *item) 78{ 79 GtkWidget *p = item; 80 struct tree_data *pd; 81 char *comps[1024]; /* We keep pointers to the components here */ 82 int i = 0, j, level,type; 83 84 /* Walk back up the tree, getting the private data */ 85 86 level = GTK_TREE(item->parent)->level; 87 88 /* Pick up this item's component info */ 89 90 pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(item)); 91 92 comps[i++] = pd->name; 93 type = pd->type; 94 95 while (level > 0 && type != SMBC_SERVER && type != SMBC_WORKGROUP) { 96 97 /* Find the parent and extract the data etc ... */ 98 99 p = GTK_WIDGET(p->parent); 100 p = GTK_WIDGET(GTK_TREE(p)->tree_owner); 101 102 pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(p)); 103 104 level = GTK_TREE(item->parent)->level; 105 106 comps[i++] = pd->name; 107 type = pd->type; 108 109 } 110 111 /* 112 * Got a list of comps now, should check that we did not hit a workgroup 113 * when we got other things as well ... Later 114 * 115 * Now, build the path 116 */ 117 118 snprintf(path_string, sizeof(path_string), "smb:/"); 119 120 for (j = i - 1; j >= 0; j--) { 121 122 strncat(path_string, "/", sizeof(path_string) - strlen(path_string)); 123 strncat(path_string, comps[j], sizeof(path_string) - strlen(path_string)); 124 125 } 126 127 fprintf(stdout, "Path string = %s\n", path_string); 128 129 return path_string; 130 131} 132 133struct tree_data *make_tree_data(guint32 type, const char *name) 134{ 135 struct tree_data *p = (struct tree_data *)malloc(sizeof(struct tree_data)); 136 137 if (p) { 138 139 p->type = type; 140 strncpy(p->name, name, sizeof(p->name)); 141 142 } 143 144 return p; 145 146} 147 148/* Note that this is called every time the user clicks on an item, 149 whether it is already selected or not. */ 150static void cb_select_child (GtkWidget *root_tree, GtkWidget *child, 151 GtkWidget *subtree) 152{ 153 gint dh, err, dirlen; 154 char dirbuf[512]; 155 struct smbc_dirent *dirp; 156 struct stat st1; 157 char path[1024], path1[1024]; 158 159 g_print ("select_child called for root tree %p, subtree %p, child %p\n", 160 root_tree, subtree, child); 161 162 /* Now, figure out what it is, and display it in the clist ... */ 163 164 gtk_clist_clear(GTK_CLIST(clist)); /* Clear the CLIST */ 165 166 /* Now, get the private data for the subtree */ 167 168 strncpy(path, get_path(child), 1024); 169 170 if ((dh = smbc_opendir(path)) < 0) { /* Handle error */ 171 172 g_print("cb_select_child: Could not open dir %s, %s\n", path, 173 strerror(errno)); 174 175 gtk_main_quit(); 176 177 return; 178 179 } 180 181 while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, 182 sizeof(dirbuf))) != 0) { 183 184 if (err < 0) { 185 186 g_print("cb_select_child: Could not read dir %s, %s\n", path, 187 strerror(errno)); 188 189 gtk_main_quit(); 190 191 return; 192 193 } 194 195 dirp = (struct smbc_dirent *)dirbuf; 196 197 while (err > 0) { 198 gchar col1[128], col2[128], col3[128], col4[128]; 199 gchar *rowdata[4] = {col1, col2, col3, col4}; 200 201 dirlen = dirp->dirlen; 202 203 /* Format each of the items ... */ 204 205 strncpy(col1, dirp->name, 128); 206 207 col2[0] = col3[0] = col4[0] = (char)0; 208 209 switch (dirp->smbc_type) { 210 211 case SMBC_WORKGROUP: 212 213 break; 214 215 case SMBC_SERVER: 216 217 strncpy(col2, (dirp->comment?dirp->comment:""), 128); 218 219 break; 220 221 case SMBC_FILE_SHARE: 222 223 strncpy(col2, (dirp->comment?dirp->comment:""), 128); 224 225 break; 226 227 case SMBC_PRINTER_SHARE: 228 229 strncpy(col2, (dirp->comment?dirp->comment:""), 128); 230 break; 231 232 case SMBC_COMMS_SHARE: 233 234 break; 235 236 case SMBC_IPC_SHARE: 237 238 break; 239 240 case SMBC_DIR: 241 case SMBC_FILE: 242 243 /* Get stats on the file/dir and see what we have */ 244 245 if ((strcmp(dirp->name, ".") != 0) && 246 (strcmp(dirp->name, "..") != 0)) { 247 248 strncpy(path1, path, sizeof(path1)); 249 strncat(path1, "/", sizeof(path) - strlen(path)); 250 strncat(path1, dirp->name, sizeof(path) - strlen(path)); 251 252 if (smbc_stat(path1, &st1) < 0) { 253 254 if (errno != EBUSY) { 255 256 g_print("cb_select_child: Could not stat file %s, %s\n", path1, 257 strerror(errno)); 258 259 gtk_main_quit(); 260 261 return; 262 263 } 264 else { 265 266 strncpy(col2, "Device or resource busy", sizeof(col2)); 267 268 } 269 } 270 else { 271 /* Now format each of the relevant things ... */ 272 273 snprintf(col2, sizeof(col2), "%c%c%c%c%c%c%c%c%c(%0X)", 274 (st1.st_mode&S_IRUSR?'r':'-'), 275 (st1.st_mode&S_IWUSR?'w':'-'), 276 (st1.st_mode&S_IXUSR?'x':'-'), 277 (st1.st_mode&S_IRGRP?'r':'-'), 278 (st1.st_mode&S_IWGRP?'w':'-'), 279 (st1.st_mode&S_IXGRP?'x':'-'), 280 (st1.st_mode&S_IROTH?'r':'-'), 281 (st1.st_mode&S_IWOTH?'w':'-'), 282 (st1.st_mode&S_IXOTH?'x':'-'), 283 st1.st_mode); 284 snprintf(col3, sizeof(col3), "%u", st1.st_size); 285 snprintf(col4, sizeof(col4), "%s", ctime(&st1.st_mtime)); 286 } 287 } 288 289 break; 290 291 default: 292 293 break; 294 } 295 296 gtk_clist_append(GTK_CLIST(clist), rowdata); 297 298 dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); 299 err -= dirlen; 300 301 } 302 303 } 304 305} 306 307/* Note that this is never called */ 308static void cb_unselect_child( GtkWidget *root_tree, 309 GtkWidget *child, 310 GtkWidget *subtree ) 311{ 312 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n", 313 root_tree, subtree, child); 314} 315 316/* for all the GtkItem:: and GtkTreeItem:: signals */ 317static void cb_itemsignal( GtkWidget *item, 318 gchar *signame ) 319{ 320 GtkWidget *real_tree, *aitem, *subtree; 321 gchar *name; 322 GtkLabel *label; 323 gint dh, err, dirlen, level; 324 char dirbuf[512]; 325 struct smbc_dirent *dirp; 326 327 label = GTK_LABEL (GTK_BIN (item)->child); 328 /* Get the text of the label */ 329 gtk_label_get (label, &name); 330 331 level = GTK_TREE(item->parent)->level; 332 333 /* Get the level of the tree which the item is in */ 334 g_print ("%s called for item %s->%p, level %d\n", signame, name, 335 item, GTK_TREE (item->parent)->level); 336 337 real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */ 338 339 if (strncmp(signame, "expand", 6) == 0) { /* Expand called */ 340 char server[128]; 341 342 if ((dh = smbc_opendir(get_path(item))) < 0) { /* Handle error */ 343 gchar errmsg[256]; 344 345 g_print("cb_itemsignal: Could not open dir %s, %s\n", get_path(item), 346 strerror(errno)); 347 348 snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not open dir %s, %s\n", get_path(item), strerror(errno)); 349 350 error_message(errmsg); 351 352 /* gtk_main_quit();*/ 353 354 return; 355 356 } 357 358 while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, 359 sizeof(dirbuf))) != 0) { 360 361 if (err < 0) { /* An error, report it */ 362 gchar errmsg[256]; 363 364 g_print("cb_itemsignal: Could not read dir smbc://, %s\n", 365 strerror(errno)); 366 367 snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not read dir smbc://, %s\n", strerror(errno)); 368 369 error_message(errmsg); 370 371 /* gtk_main_quit();*/ 372 373 return; 374 375 } 376 377 dirp = (struct smbc_dirent *)dirbuf; 378 379 while (err > 0) { 380 struct tree_data *my_data; 381 382 dirlen = dirp->dirlen; 383 384 my_data = make_tree_data(dirp->smbc_type, dirp->name); 385 386 if (!my_data) { 387 388 g_print("Could not allocate space for tree_data: %s\n", 389 dirp->name); 390 391 gtk_main_quit(); 392 return; 393 394 } 395 396 aitem = gtk_tree_item_new_with_label(dirp->name); 397 398 /* Connect all GtkItem:: and GtkTreeItem:: signals */ 399 gtk_signal_connect (GTK_OBJECT(aitem), "select", 400 GTK_SIGNAL_FUNC(cb_itemsignal), "select"); 401 gtk_signal_connect (GTK_OBJECT(aitem), "deselect", 402 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); 403 gtk_signal_connect (GTK_OBJECT(aitem), "toggle", 404 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); 405 gtk_signal_connect (GTK_OBJECT(aitem), "expand", 406 GTK_SIGNAL_FUNC(cb_itemsignal), "expand"); 407 gtk_signal_connect (GTK_OBJECT(aitem), "collapse", 408 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse"); 409 /* Add it to the parent tree */ 410 gtk_tree_append (GTK_TREE(real_tree), aitem); 411 412 gtk_widget_show (aitem); 413 414 gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data); 415 416 fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen); 417 418 if (dirp->smbc_type != SMBC_FILE && 419 dirp->smbc_type != SMBC_IPC_SHARE && 420 (strcmp(dirp->name, ".") != 0) && 421 (strcmp(dirp->name, "..") !=0)){ 422 423 subtree = gtk_tree_new(); 424 gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree); 425 426 gtk_signal_connect(GTK_OBJECT(subtree), "select_child", 427 GTK_SIGNAL_FUNC(cb_select_child), real_tree); 428 gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child", 429 GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); 430 431 } 432 433 dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); 434 err -= dirlen; 435 436 } 437 438 } 439 440 smbc_closedir(dh); 441 442 } 443 else if (strncmp(signame, "collapse", 8) == 0) { 444 GtkWidget *subtree = gtk_tree_new(); 445 446 gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children); 447 448 gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); 449 450 gtk_signal_connect (GTK_OBJECT(subtree), "select_child", 451 GTK_SIGNAL_FUNC(cb_select_child), real_tree); 452 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", 453 GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); 454 455 } 456 457} 458 459static void cb_selection_changed( GtkWidget *tree ) 460{ 461 GList *i; 462 463 g_print ("selection_change called for tree %p\n", tree); 464 g_print ("selected objects are:\n"); 465 466 i = GTK_TREE_SELECTION(tree); 467 while (i){ 468 gchar *name; 469 GtkLabel *label; 470 GtkWidget *item; 471 472 /* Get a GtkWidget pointer from the list node */ 473 item = GTK_WIDGET (i->data); 474 label = GTK_LABEL (GTK_BIN (item)->child); 475 gtk_label_get (label, &name); 476 g_print ("\t%s on level %d\n", name, GTK_TREE 477 (item->parent)->level); 478 i = i->next; 479 } 480} 481 482/* 483 * Expand or collapse the whole network ... 484 */ 485static void cb_wholenet(GtkWidget *item, gchar *signame) 486{ 487 GtkWidget *real_tree, *aitem, *subtree; 488 gchar *name; 489 GtkLabel *label; 490 gint dh, err, dirlen; 491 char dirbuf[512]; 492 struct smbc_dirent *dirp; 493 494 label = GTK_LABEL (GTK_BIN (item)->child); 495 gtk_label_get (label, &name); 496 g_print ("%s called for item %s->%p, level %d\n", signame, name, 497 item, GTK_TREE (item->parent)->level); 498 499 real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */ 500 501 if (strncmp(signame, "expand", 6) == 0) { /* Expand called */ 502 503 if ((dh = smbc_opendir("smb://")) < 0) { /* Handle error */ 504 505 g_print("cb_wholenet: Could not open dir smbc://, %s\n", 506 strerror(errno)); 507 508 gtk_main_quit(); 509 510 return; 511 512 } 513 514 while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, 515 sizeof(dirbuf))) != 0) { 516 517 if (err < 0) { /* An error, report it */ 518 519 g_print("cb_wholenet: Could not read dir smbc://, %s\n", 520 strerror(errno)); 521 522 gtk_main_quit(); 523 524 return; 525 526 } 527 528 dirp = (struct smbc_dirent *)dirbuf; 529 530 while (err > 0) { 531 struct tree_data *my_data; 532 533 dirlen = dirp->dirlen; 534 535 my_data = make_tree_data(dirp->smbc_type, dirp->name); 536 537 aitem = gtk_tree_item_new_with_label(dirp->name); 538 539 /* Connect all GtkItem:: and GtkTreeItem:: signals */ 540 gtk_signal_connect (GTK_OBJECT(aitem), "select", 541 GTK_SIGNAL_FUNC(cb_itemsignal), "select"); 542 gtk_signal_connect (GTK_OBJECT(aitem), "deselect", 543 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); 544 gtk_signal_connect (GTK_OBJECT(aitem), "toggle", 545 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); 546 gtk_signal_connect (GTK_OBJECT(aitem), "expand", 547 GTK_SIGNAL_FUNC(cb_itemsignal), "expand"); 548 gtk_signal_connect (GTK_OBJECT(aitem), "collapse", 549 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse"); 550 551 gtk_tree_append (GTK_TREE(real_tree), aitem); 552 /* Show it - this can be done at any time */ 553 gtk_widget_show (aitem); 554 555 gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data); 556 557 fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen); 558 559 subtree = gtk_tree_new(); 560 561 gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree); 562 563 gtk_signal_connect(GTK_OBJECT(subtree), "select_child", 564 GTK_SIGNAL_FUNC(cb_select_child), real_tree); 565 gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child", 566 GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); 567 568 dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); 569 err -= dirlen; 570 571 } 572 573 } 574 575 smbc_closedir(dh); 576 577 } 578 else { /* Must be collapse ... FIXME ... */ 579 GtkWidget *subtree = gtk_tree_new(); 580 581 gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children); 582 583 gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); 584 585 gtk_signal_connect (GTK_OBJECT(subtree), "select_child", 586 GTK_SIGNAL_FUNC(cb_select_child), real_tree); 587 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", 588 GTK_SIGNAL_FUNC(cb_unselect_child), real_tree); 589 590 591 } 592 593} 594 595/* Should put up a dialog box to ask the user for username and password */ 596 597static void 598auth_fn(const char *server, const char *share, 599 char *workgroup, int wgmaxlen, char *username, int unmaxlen, 600 char *password, int pwmaxlen) 601{ 602 603 strncpy(username, "test", unmaxlen); 604 strncpy(password, "test", pwmaxlen); 605 606} 607 608static char *col_titles[] = { 609 "Name", "Attributes", "Size", "Modification Date", 610}; 611 612int main( int argc, 613 char *argv[] ) 614{ 615 GtkWidget *window, *scrolled_win, *scrolled_win2, *tree; 616 GtkWidget *subtree, *item, *main_hbox, *r_pane, *l_pane; 617 gint err, dh; 618 gint i; 619 char dirbuf[512]; 620 struct smbc_dirent *dirp; 621 622 gtk_init (&argc, &argv); 623 624 /* Init the smbclient library */ 625 626 err = smbc_init(auth_fn, 10); 627 628 /* Print an error response ... */ 629 630 if (err < 0) { 631 632 fprintf(stderr, "smbc_init returned %s (%i)\nDo you have a ~/.smb/smb.conf file?\n", strerror(errno), errno); 633 exit(1); 634 635 } 636 637 /* a generic toplevel window */ 638 window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 639 gtk_widget_set_name(window, "main browser window"); 640 gtk_signal_connect (GTK_OBJECT(window), "delete_event", 641 GTK_SIGNAL_FUNC (gtk_main_quit), NULL); 642 gtk_window_set_title(GTK_WINDOW(window), "The Linux Windows Network Browser"); 643 gtk_widget_set_usize(GTK_WIDGET(window), 750, -1); 644 gtk_container_set_border_width (GTK_CONTAINER(window), 5); 645 646 gtk_widget_show (window); 647 648 /* A container for the two panes ... */ 649 650 main_hbox = gtk_hbox_new(FALSE, 1); 651 gtk_container_border_width(GTK_CONTAINER(main_hbox), 1); 652 gtk_container_add(GTK_CONTAINER(window), main_hbox); 653 654 gtk_widget_show(main_hbox); 655 656 l_pane = gtk_hpaned_new(); 657 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size); 658 r_pane = gtk_hpaned_new(); 659 gtk_paned_gutter_size(GTK_PANED(r_pane), (GTK_PANED(r_pane))->handle_size); 660 gtk_container_add(GTK_CONTAINER(main_hbox), l_pane); 661 gtk_widget_show(l_pane); 662 663 /* A generic scrolled window */ 664 scrolled_win = gtk_scrolled_window_new (NULL, NULL); 665 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), 666 GTK_POLICY_AUTOMATIC, 667 GTK_POLICY_AUTOMATIC); 668 gtk_widget_set_usize (scrolled_win, 150, 200); 669 gtk_container_add (GTK_CONTAINER(l_pane), scrolled_win); 670 gtk_widget_show (scrolled_win); 671 672 /* Another generic scrolled window */ 673 scrolled_win2 = gtk_scrolled_window_new (NULL, NULL); 674 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2), 675 GTK_POLICY_AUTOMATIC, 676 GTK_POLICY_AUTOMATIC); 677 gtk_widget_set_usize (scrolled_win2, 150, 200); 678 gtk_paned_add2 (GTK_PANED(l_pane), scrolled_win2); 679 gtk_widget_show (scrolled_win2); 680 681 /* Create the root tree */ 682 tree = gtk_tree_new(); 683 g_print ("root tree is %p\n", tree); 684 /* connect all GtkTree:: signals */ 685 gtk_signal_connect (GTK_OBJECT(tree), "select_child", 686 GTK_SIGNAL_FUNC(cb_select_child), tree); 687 gtk_signal_connect (GTK_OBJECT(tree), "unselect_child", 688 GTK_SIGNAL_FUNC(cb_unselect_child), tree); 689 gtk_signal_connect (GTK_OBJECT(tree), "selection_changed", 690 GTK_SIGNAL_FUNC(cb_selection_changed), tree); 691 /* Add it to the scrolled window */ 692 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win), 693 tree); 694 /* Set the selection mode */ 695 gtk_tree_set_selection_mode (GTK_TREE(tree), 696 GTK_SELECTION_MULTIPLE); 697 /* Show it */ 698 gtk_widget_show (tree); 699 700 /* Now, create a clist and attach it to the second pane */ 701 702 clist = gtk_clist_new_with_titles(4, col_titles); 703 704 gtk_container_add (GTK_CONTAINER(scrolled_win2), clist); 705 706 gtk_widget_show(clist); 707 708 /* Now, build the top level display ... */ 709 710 if ((dh = smbc_opendir("smb://")) < 0) { 711 712 fprintf(stderr, "Could not list workgroups: smb://: %s\n", 713 strerror(errno)); 714 715 exit(1); 716 717 } 718 719 /* Create a tree item for Whole Network */ 720 721 item = gtk_tree_item_new_with_label ("Whole Network"); 722 /* Connect all GtkItem:: and GtkTreeItem:: signals */ 723 gtk_signal_connect (GTK_OBJECT(item), "select", 724 GTK_SIGNAL_FUNC(cb_itemsignal), "select"); 725 gtk_signal_connect (GTK_OBJECT(item), "deselect", 726 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); 727 gtk_signal_connect (GTK_OBJECT(item), "toggle", 728 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); 729 gtk_signal_connect (GTK_OBJECT(item), "expand", 730 GTK_SIGNAL_FUNC(cb_wholenet), "expand"); 731 gtk_signal_connect (GTK_OBJECT(item), "collapse", 732 GTK_SIGNAL_FUNC(cb_wholenet), "collapse"); 733 /* Add it to the parent tree */ 734 gtk_tree_append (GTK_TREE(tree), item); 735 /* Show it - this can be done at any time */ 736 gtk_widget_show (item); 737 738 subtree = gtk_tree_new(); /* A subtree for Whole Network */ 739 740 gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); 741 742 gtk_signal_connect (GTK_OBJECT(subtree), "select_child", 743 GTK_SIGNAL_FUNC(cb_select_child), tree); 744 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", 745 GTK_SIGNAL_FUNC(cb_unselect_child), tree); 746 747 /* Now, get the items in smb:/// and add them to the tree */ 748 749 while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf, 750 sizeof(dirbuf))) != 0) { 751 752 if (err < 0) { /* Handle the error */ 753 754 fprintf(stderr, "Could not read directory for smbc:///: %s\n", 755 strerror(errno)); 756 757 exit(1); 758 759 } 760 761 dirp = (struct smbc_dirent *)dirbuf; 762 763 fprintf(stdout, "Dir len: %u\n", err); 764 765 while (err > 0) { /* Extract each entry and make a sub-tree */ 766 struct tree_data *my_data; 767 int dirlen = dirp->dirlen; 768 769 my_data = make_tree_data(dirp->smbc_type, dirp->name); 770 771 item = gtk_tree_item_new_with_label(dirp->name); 772 /* Connect all GtkItem:: and GtkTreeItem:: signals */ 773 gtk_signal_connect (GTK_OBJECT(item), "select", 774 GTK_SIGNAL_FUNC(cb_itemsignal), "select"); 775 gtk_signal_connect (GTK_OBJECT(item), "deselect", 776 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect"); 777 gtk_signal_connect (GTK_OBJECT(item), "toggle", 778 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle"); 779 gtk_signal_connect (GTK_OBJECT(item), "expand", 780 GTK_SIGNAL_FUNC(cb_itemsignal), "expand"); 781 gtk_signal_connect (GTK_OBJECT(item), "collapse", 782 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse"); 783 /* Add it to the parent tree */ 784 gtk_tree_append (GTK_TREE(tree), item); 785 /* Show it - this can be done at any time */ 786 gtk_widget_show (item); 787 788 gtk_object_set_user_data(GTK_OBJECT(item), (gpointer)my_data); 789 790 fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen); 791 792 subtree = gtk_tree_new(); 793 794 gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree); 795 796 gtk_signal_connect (GTK_OBJECT(subtree), "select_child", 797 GTK_SIGNAL_FUNC(cb_select_child), tree); 798 gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child", 799 GTK_SIGNAL_FUNC(cb_unselect_child), tree); 800 801 dirp = (struct smbc_dirent *) ((char *) dirp + dirlen); 802 err -= dirlen; 803 804 } 805 806 } 807 808 smbc_closedir(dh); /* FIXME, check for error :-) */ 809 810 /* Show the window and loop endlessly */ 811 gtk_main(); 812 return 0; 813} 814/* example-end */ 815