2 * Unix SMB/CIFS implementation.
3 * Join Support (gtk + netapi)
4 * Copyright (C) Guenther Deschner 2007
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
29 #include <glib/gprintf.h>
33 #define MAX_CRED_LEN 256
34 #define MAX_NETBIOS_NAME_LEN 15
36 #define SAMBA_ICON_PATH "/usr/share/pixmaps/samba/samba.ico"
37 #define SAMBA_IMAGE_PATH "/usr/share/pixmaps/samba/logo.png"
39 #define WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
40 #define WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE ( 0x00000004 )
41 #define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
42 #define WKSSVC_JOIN_FLAGS_JOIN_TYPE ( 0x00000001 )
44 #define NetSetupWorkgroupName ( 2 )
45 #define NetSetupDomainName ( 3 )
47 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
49 struct srvsvc_NetSrvInfo1005 {
50 const char *comment;/* [unique,charset(UTF16)] */
53 static gboolean verbose = FALSE;
55 typedef struct join_state {
56 struct libnetapi_ctx *ctx;
57 GtkWidget *window_main;
58 GtkWidget *window_parent;
59 GtkWidget *window_do_change;
60 GtkWidget *window_creds_prompt;
61 GtkWidget *entry_account;
62 GtkWidget *entry_password;
63 GtkWidget *entry_domain;
64 GtkWidget *entry_workgroup;
66 GtkWidget *button_apply;
67 GtkWidget *button_ok_creds;
68 GtkWidget *label_reboot;
69 GtkWidget *label_current_name_buffer;
70 GtkWidget *label_current_name_type;
71 GtkWidget *label_full_computer_name;
72 uint16_t name_type_initial;
73 uint16_t name_type_new;
74 char *name_buffer_initial;
75 char *name_buffer_new;
84 gboolean settings_changed;
85 gboolean hostname_changed;
88 static void debug(const char *format, ...)
96 va_start(args, format);
97 g_vprintf(format, args);
101 static gboolean callback_delete_event(GtkWidget *widget,
109 static void callback_do_close(GtkWidget *widget,
112 debug("Closing now...\n");
113 gtk_widget_destroy(data);
116 static void free_join_state(struct join_state *s)
118 SAFE_FREE(s->name_buffer_initial);
119 SAFE_FREE(s->name_buffer_new);
120 SAFE_FREE(s->password);
121 SAFE_FREE(s->account);
122 SAFE_FREE(s->comment);
123 SAFE_FREE(s->comment_new);
124 SAFE_FREE(s->my_fqdn);
125 SAFE_FREE(s->my_dnsdomain);
126 SAFE_FREE(s->my_hostname);
130 static void do_cleanup(struct join_state *state)
132 libnetapi_free(state->ctx);
133 free_join_state(state);
136 static void callback_apply_description_change(GtkWidget *widget,
139 struct join_state *state = (struct join_state *)data;
140 NET_API_STATUS status = 0;
141 uint32_t parm_err = 0;
142 struct srvsvc_NetSrvInfo1005 info1005;
145 info1005.comment = state->comment_new;
147 status = NetServerSetInfo(NULL, 1005, (uint8_t *)&info1005, &parm_err);
149 debug("NetServerSetInfo failed with: %s\n",
150 libnetapi_errstr(state->ctx, status));
151 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
152 GTK_DIALOG_DESTROY_WITH_PARENT,
155 "Failed to change computer description: %s.",
156 libnetapi_errstr(state->ctx, status));
157 g_signal_connect_swapped(dialog, "response",
158 G_CALLBACK(gtk_widget_destroy),
161 gtk_widget_show(dialog);
165 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
168 static void callback_do_exit(GtkWidget *widget,
173 struct join_state *state = (struct join_state *)data;
175 if (!state->settings_changed) {
176 callback_delete_event(NULL, NULL, NULL);
180 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
181 GTK_DIALOG_DESTROY_WITH_PARENT,
182 GTK_MESSAGE_QUESTION,
184 "You must restart your computer before the new settings will take effect.");
185 result = gtk_dialog_run(GTK_DIALOG(dialog));
187 case GTK_RESPONSE_YES:
188 g_print("would reboot here\n");
190 case GTK_RESPONSE_NO:
194 gtk_widget_destroy(dialog);
195 gtk_widget_destroy(state->window_main);
201 static void callback_do_reboot(GtkWidget *widget,
206 struct join_state *state = (struct join_state *)data2;
208 debug("callback_do_reboot\n");
210 state->settings_changed = TRUE;
211 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
212 GTK_DIALOG_DESTROY_WITH_PARENT,
215 "You must restart this computer for the changes to take effect.");
217 g_signal_connect_swapped(dialog, "response",
218 G_CALLBACK(gtk_widget_destroy),
221 debug("showing dialog\n");
222 gtk_widget_show(dialog);
224 gtk_dialog_run(GTK_DIALOG(dialog));
225 gtk_widget_destroy(dialog);
228 gtk_label_set_text(GTK_LABEL(state->label_reboot), "Changes will take effect after you restart this computer");
230 debug("destroying do_change window\n");
231 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
238 status = NetGetJoinInformation(NULL, &buffer, &type);
240 g_print("failed to query status\n");
244 debug("got new status: %s\n", buffer);
246 SAFE_FREE(state->name_buffer_new);
247 state->name_buffer_new = strdup(buffer);
249 state->name_type_new = type;
251 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer), state->name_buffer_new);
252 if (state->name_type_new == 3) {
253 gtk_label_set_text(GTK_LABEL(state->label_current_name_type), "Domain:");
255 gtk_label_set_text(GTK_LABEL(state->label_current_name_type), "Workgroup:");
260 static void callback_return_username(GtkWidget *widget,
263 const gchar *entry_text;
264 struct join_state *state = (struct join_state *)data;
268 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
269 debug("callback_return_username: %s\n", entry_text);
270 SAFE_FREE(state->account);
271 state->account = strdup(entry_text);
274 static void callback_return_username_and_enter(GtkWidget *widget,
277 const gchar *entry_text;
278 struct join_state *state = (struct join_state *)data;
282 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
283 debug("callback_return_username: %s\n", entry_text);
284 SAFE_FREE(state->account);
285 state->account = strdup(entry_text);
286 g_signal_emit_by_name(state->button_ok_creds, "clicked");
289 static void callback_return_password(GtkWidget *widget,
292 const gchar *entry_text;
293 struct join_state *state = (struct join_state *)data;
297 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
298 #ifdef DEBUG_PASSWORD
299 debug("callback_return_password: %s\n", entry_text);
301 debug("callback_return_password: (not printed)\n");
303 SAFE_FREE(state->password);
304 state->password = strdup(entry_text);
307 static void callback_return_password_and_enter(GtkWidget *widget,
310 const gchar *entry_text;
311 struct join_state *state = (struct join_state *)data;
315 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
316 #ifdef DEBUG_PASSWORD
317 debug("callback_return_password: %s\n", entry_text);
319 debug("callback_return_password: (not printed)\n");
321 SAFE_FREE(state->password);
322 state->password = strdup(entry_text);
323 g_signal_emit_by_name(state->button_ok_creds, "clicked");
326 static void callback_do_hostname_change(GtkWidget *widget,
330 const char *str = NULL;
332 struct join_state *state = (struct join_state *)data;
334 switch (state->name_type_initial) {
335 case NetSetupDomainName:
336 str = "To be implemented: call NetRenameMachineInDomain\n";
338 case NetSetupWorkgroupName:
339 str = "To be implemented: call SetComputerNameEx\n";
345 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
346 GTK_DIALOG_DESTROY_WITH_PARENT,
351 g_signal_connect_swapped(dialog, "response",
352 G_CALLBACK(gtk_widget_destroy),
354 gtk_widget_show(dialog);
357 static void callback_do_join(GtkWidget *widget,
362 NET_API_STATUS status;
363 const char *err_str = NULL;
364 uint32_t join_flags = 0;
365 uint32_t unjoin_flags = 0;
366 gboolean domain_join = FALSE;
367 gboolean try_unjoin = FALSE;
368 const char *domain_or_workgroup = NULL;
370 struct join_state *state = (struct join_state *)data;
372 callback_return_username(state->entry_account, state);
373 callback_return_password(state->entry_password, state);
375 if (state->window_creds_prompt) {
376 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
379 if (state->name_type_new == NetSetupDomainName) {
381 join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
382 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
383 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED; /* for testing */
384 domain_or_workgroup = "domain";
386 domain_or_workgroup = "workgroup";
389 if ((state->name_type_initial == NetSetupDomainName) &&
390 (state->name_type_new == NetSetupWorkgroupName)) {
392 unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
393 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
396 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
398 state->name_buffer_new,
401 debug("as %s ", state->account);
402 #ifdef DEBUG_PASSWORD
403 debug("with %s ", state->password);
409 debug("callback_do_join: Unjoining\n");
411 status = NetUnjoinDomain(NULL,
416 err_str = libnetapi_errstr(state->ctx, status);
417 g_print("callback_do_join: failed to unjoin (%s)\n",
420 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
421 GTK_DIALOG_DESTROY_WITH_PARENT,
424 "The following error occured attempting to unjoin the %s: \"%s\": %s",
426 state->name_buffer_new,
429 g_signal_connect_swapped(dialog, "response",
430 G_CALLBACK(gtk_widget_destroy),
433 gtk_widget_show(dialog);
439 status = NetJoinDomain(NULL,
440 state->name_buffer_new,
446 err_str = libnetapi_errstr(state->ctx, status);
447 g_print("callback_do_join: failed to join (%s)\n", err_str);
449 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
450 GTK_DIALOG_DESTROY_WITH_PARENT,
453 "The following error occured attempting to join the %s: \"%s\": %s",
455 state->name_buffer_new,
458 g_signal_connect_swapped(dialog, "response",
459 G_CALLBACK(gtk_widget_destroy),
462 gtk_widget_show(dialog);
467 debug("callback_do_join: Successfully joined %s\n",
468 domain_or_workgroup);
470 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
471 GTK_DIALOG_DESTROY_WITH_PARENT,
474 "Welcome to the %s %s.",
475 state->name_buffer_new,
476 domain_or_workgroup);
478 gtk_dialog_run(GTK_DIALOG(dialog));
479 gtk_widget_destroy(dialog);
481 callback_do_reboot(NULL, state->window_parent, state);
484 static void callback_creds_prompt(GtkWidget *widget,
493 struct join_state *state = (struct join_state *)data;
495 debug("callback_creds_prompt:\n");
497 state->window_parent = state->window_do_change;
499 if (state->hostname_changed) {
500 return callback_do_hostname_change(NULL, state);
503 if ((state->name_type_initial != NetSetupDomainName) &&
504 (state->name_type_new != NetSetupDomainName)) {
505 return callback_do_join(NULL, state);
508 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
510 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
511 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
512 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
513 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
514 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
515 /* gtk_window_set_icon_name(GTK_WIDGET(window), GTK_STOCK_DIALOG_AUTHENTICATION); */
516 state->window_creds_prompt = window;
518 g_signal_connect(G_OBJECT(window), "delete_event",
519 G_CALLBACK(callback_do_close), window);
521 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
523 box1 = gtk_vbox_new(FALSE, 0);
525 gtk_container_add(GTK_CONTAINER(window), box1);
527 if ((state->name_type_initial == NetSetupDomainName) &&
528 (state->name_type_new == NetSetupWorkgroupName)) {
529 label = gtk_label_new("Enter the name and password of an account with permission to leave the domain.\n");
531 label = gtk_label_new("Enter the name and password of an account with permission to join the domain.\n");
533 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
534 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
536 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
538 gtk_widget_show(label);
541 label = gtk_label_new("User name:");
542 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
543 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
544 gtk_widget_show(label);
546 state->entry_account = gtk_entry_new();
547 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
548 g_signal_connect(G_OBJECT(state->entry_account), "activate",
549 G_CALLBACK(callback_return_username_and_enter),
551 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
552 0, GTK_ENTRY(state->entry_account)->text_length);
553 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
554 gtk_widget_show(state->entry_account);
557 label = gtk_label_new("Password:");
558 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
559 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
560 gtk_widget_show(label);
562 state->entry_password = gtk_entry_new();
563 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
564 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
565 g_signal_connect(G_OBJECT(state->entry_password), "activate",
566 G_CALLBACK(callback_return_password_and_enter),
568 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
569 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
570 0, GTK_ENTRY(state->entry_password)->text_length);
571 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
572 gtk_widget_show(state->entry_password);
574 bbox = gtk_hbutton_box_new();
575 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
576 gtk_container_add(GTK_CONTAINER(box1), bbox);
577 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
578 gtk_box_set_spacing(GTK_BOX(bbox), 10);
580 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
581 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
582 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
583 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
584 G_CALLBACK(callback_do_join),
586 gtk_widget_show(state->button_ok_creds);
588 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
589 gtk_container_add(GTK_CONTAINER(bbox), button);
590 g_signal_connect(G_OBJECT(button), "clicked",
591 G_CALLBACK(callback_do_close), (gpointer) window);
592 gtk_widget_show_all(window);
595 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
598 const gchar *entry_text = NULL;
600 struct join_state *state = (struct join_state *)data;
602 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
603 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
604 if (!entry_text || entry_text[0] == 0) {
605 state->hostname_changed = FALSE;
606 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
609 if (strcasecmp(state->my_hostname, entry_text) == 0) {
610 state->hostname_changed = FALSE;
611 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
614 state->hostname_changed = TRUE;
615 if (state->name_type_initial == NetSetupDomainName) {
616 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
618 asprintf(&str, "%s.", entry_text);
620 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
623 if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
624 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
628 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
631 const gchar *entry_text = NULL;
632 struct join_state *state = (struct join_state *)data;
633 int string_unchanged = 0;
635 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
636 debug("callback_enter_computer_description_and_unlock: %s\n",
639 if (!entry_text || entry_text[0] == 0) {
640 string_unchanged = 1;
641 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
646 if (entry_text && strcasecmp(state->comment, entry_text) == 0) {
647 string_unchanged = 1;
648 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
653 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
654 SAFE_FREE(state->comment_new);
655 state->comment_new = strdup(entry_text);
660 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
663 const gchar *entry_text = NULL;
664 struct join_state *state = (struct join_state *)data;
666 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
667 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
668 if (!entry_text || entry_text[0] == 0) {
669 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
672 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
673 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
676 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
677 SAFE_FREE(state->name_buffer_new);
678 state->name_buffer_new = strdup(entry_text);
679 state->name_type_new = NetSetupWorkgroupName;
682 static void callback_enter_domain_and_unlock(GtkWidget *widget,
685 const gchar *entry_text = NULL;
686 struct join_state *state = (struct join_state *)data;
688 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
689 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
690 if (!entry_text || entry_text[0] == 0) {
691 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
694 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
695 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
698 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
699 SAFE_FREE(state->name_buffer_new);
700 state->name_buffer_new = strdup(entry_text);
701 state->name_type_new = NetSetupDomainName;
704 static void callback_continue(GtkWidget *widget,
707 struct join_state *state = (struct join_state *)data;
709 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
710 g_signal_emit_by_name(state->button_ok, "clicked");
713 static void callback_apply_continue(GtkWidget *widget,
716 struct join_state *state = (struct join_state *)data;
718 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
719 g_signal_emit_by_name(state->button_apply, "clicked");
722 static void callback_do_join_workgroup(GtkWidget *widget,
725 struct join_state *state = (struct join_state *)data;
726 debug("callback_do_join_workgroup choosen\n");
727 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
728 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
729 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
730 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
733 static void callback_do_join_domain(GtkWidget *widget,
736 struct join_state *state = (struct join_state *)data;
737 debug("callback_do_join_domain choosen\n");
738 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
739 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
740 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
741 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
744 static void callback_do_change(GtkWidget *widget,
750 GtkWidget *button_workgroup;
751 GtkWidget *button_domain;
754 GtkWidget *frame_horz;
759 struct join_state *state = (struct join_state *)data;
761 debug("callback_do_change called\n");
763 if (state->server_role == 3) {
765 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
766 GTK_DIALOG_DESTROY_WITH_PARENT,
769 "Domain controller cannot be moved from one domain to another, they must first be demoted. Renaming this domain controller may cause it to become temporarily unavailable to users and computers. For information on renaming domain controllers, including alternate renaming methods, see Help and Support. To continue renaming this domain controller, click OK.");
770 g_signal_connect_swapped(dialog, "response",
771 G_CALLBACK(gtk_widget_destroy),
774 gtk_widget_show(dialog);
778 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
779 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
781 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
782 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
783 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 500); /* breite * höhe */
784 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
786 g_signal_connect(G_OBJECT(window), "delete_event",
787 G_CALLBACK(callback_do_close), window);
789 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
791 box1 = gtk_vbox_new(FALSE, 0);
792 gtk_container_add(GTK_CONTAINER(window), box1);
794 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
795 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
796 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
797 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
798 gtk_widget_show(label);
801 label = gtk_label_new("Computer name:");
802 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
803 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
804 gtk_widget_show(label);
806 state->label_full_computer_name = gtk_label_new(NULL);
808 entry = gtk_entry_new();
809 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
810 g_signal_connect(G_OBJECT(entry), "changed",
811 G_CALLBACK(callback_enter_hostname_and_unlock),
813 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
814 gtk_editable_select_region(GTK_EDITABLE(entry),
815 0, GTK_ENTRY(entry)->text_length);
817 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
818 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
819 gtk_widget_show(entry);
822 /* FULL COMPUTER NAME */
823 label = gtk_label_new("Full computer name:");
824 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
825 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
826 gtk_widget_show(label);
829 const gchar *entry_text;
831 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
832 if (state->name_type_initial == NetSetupDomainName) {
833 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
835 asprintf(&str, "%s.", entry_text);
837 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
839 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
840 gtk_box_pack_start(GTK_BOX(box1), state->label_full_computer_name, TRUE, TRUE, 0);
841 gtk_widget_show(state->label_full_computer_name);
845 frame_horz = gtk_frame_new ("Member Of");
846 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
848 vbox = gtk_vbox_new(FALSE, 0);
849 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
850 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
853 state->entry_workgroup = gtk_entry_new();
854 state->entry_domain = gtk_entry_new();
857 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
858 if (state->name_type_initial == NetSetupDomainName) {
859 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
861 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
862 g_signal_connect(G_OBJECT(button_domain), "clicked",
863 G_CALLBACK(callback_do_join_domain),
867 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
868 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
869 G_CALLBACK(callback_enter_domain_and_unlock),
871 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
872 G_CALLBACK(callback_continue),
874 if (state->name_type_initial == NetSetupDomainName) {
875 gtk_entry_set_text(GTK_ENTRY(state->entry_domain), state->name_buffer_initial);
876 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
877 gtk_widget_set_sensitive(state->entry_domain, TRUE);
879 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
880 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
881 gtk_widget_show(state->entry_domain);
883 gtk_widget_show(button_domain);
886 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
887 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
888 if (state->name_type_initial == NetSetupWorkgroupName) {
889 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
891 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
892 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
893 G_CALLBACK(callback_do_join_workgroup),
896 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup), MAX_NETBIOS_NAME_LEN);
897 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
898 G_CALLBACK(callback_enter_workgroup_and_unlock),
900 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
901 G_CALLBACK(callback_continue),
904 if (state->name_type_initial == NetSetupWorkgroupName) {
905 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup), state->name_buffer_initial);
906 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
907 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
909 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
910 gtk_widget_show(state->entry_workgroup);
912 gtk_widget_show(button_workgroup);
915 bbox = gtk_hbutton_box_new();
916 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
917 gtk_container_add(GTK_CONTAINER(box1), bbox);
918 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
919 gtk_box_set_spacing(GTK_BOX(bbox), 10);
921 state->window_do_change = window;
922 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE); /* !!! */
923 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
924 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
925 G_CALLBACK(callback_creds_prompt),
928 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
929 gtk_container_add(GTK_CONTAINER(bbox), button);
930 g_signal_connect(G_OBJECT(button), "clicked",
931 G_CALLBACK(callback_do_close),
934 gtk_widget_show_all(window);
938 static void callback_do_about(GtkWidget *widget,
942 GError *error = NULL;
944 debug("callback_do_about called\n");
946 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
949 g_print("failed to load logo from %s: %s\n",
950 SAMBA_IMAGE_PATH, error->message);
953 gtk_show_about_dialog(data,
955 "version", "3.2.0pre2-GIT-904a90-test",
956 "copyright", "Copyright Andrew Tridgell and the Samba Team 1992-2007",
957 "website", "http://www.samba.org",
960 "comments", "Samba gtk domain join utility",
964 static int draw_main_window(struct join_state *state)
969 GtkWidget *main_vbox;
977 GError *error = NULL;
979 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
982 g_print("failed to load logo from %s : %s\n",
983 SAMBA_ICON_PATH, error->message);
987 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH);
989 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
992 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
993 state->window_main = window;
995 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
996 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600); /* breite * höhe */
997 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
998 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1000 g_signal_connect(G_OBJECT(window), "delete_event",
1001 G_CALLBACK(callback_delete_event), NULL);
1003 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1005 main_vbox = gtk_vbox_new(FALSE, 10);
1006 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1009 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1010 gtk_widget_show(image);
1013 hbox = gtk_hbox_new(FALSE, 10);
1014 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1017 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1018 gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
1019 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1020 gtk_widget_show(image);
1023 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1024 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1025 gtk_widget_set_size_request(GTK_WIDGET(label), 500, 40);
1026 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1027 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1028 gtk_widget_show(label);
1031 gtk_widget_show(hbox);
1033 vbox = gtk_vbox_new(FALSE, 0);
1034 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1035 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1038 table = gtk_table_new(6, 3, TRUE);
1039 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1040 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1041 gtk_container_add(GTK_CONTAINER(vbox), table);
1045 label = gtk_label_new("Computer description:");
1046 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1047 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1048 gtk_widget_show(label);
1050 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1053 entry = gtk_entry_new();
1054 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1055 g_signal_connect(G_OBJECT(entry), "changed",
1056 G_CALLBACK(callback_enter_computer_description_and_unlock),
1058 g_signal_connect(G_OBJECT(entry), "activate",
1059 G_CALLBACK(callback_apply_continue),
1062 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1063 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1064 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1065 gtk_widget_show(entry);
1069 label = gtk_label_new("For example: \"Samba \%v\".");
1070 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1071 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1072 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1073 gtk_widget_show(label);
1076 label = gtk_label_new("Full computer name:");
1077 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1078 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1079 gtk_widget_show(label);
1084 if (state->name_type_initial == NetSetupDomainName) {
1085 asprintf(&str, "%s.%s", state->my_hostname,
1086 state->my_dnsdomain);
1088 asprintf(&str, "%s.", state->my_hostname);
1091 label = gtk_label_new(str);
1093 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1094 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1095 gtk_widget_show(label);
1099 if (state->name_type_initial == NetSetupDomainName) {
1100 label = gtk_label_new("Domain:");
1102 label = gtk_label_new("Workgroup:");
1104 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1105 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1106 gtk_widget_show(label);
1107 state->label_current_name_type = label;
1110 label = gtk_label_new(state->name_buffer_initial);
1111 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1112 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1113 gtk_widget_show(label);
1114 state->label_current_name_buffer = label;
1117 hbox = gtk_hbox_new(FALSE, 0);
1118 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1119 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1120 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1126 bbox = gtk_hbutton_box_new();
1127 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1128 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1129 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1130 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1132 button = gtk_button_new_with_mnemonic("Ch_ange");
1133 g_signal_connect(G_OBJECT(button), "clicked",
1134 G_CALLBACK(callback_do_change),
1136 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1137 gtk_widget_show(button);
1139 /* Label (hidden) */
1140 state->label_reboot = gtk_label_new(NULL);
1141 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1142 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1143 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1144 gtk_widget_show(state->label_reboot);
1147 gtk_box_pack_start(GTK_BOX(vbox),
1148 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1157 frame = gtk_frame_new(NULL);
1158 bbox2 = gtk_hbutton_box_new();
1160 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1161 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1163 /* Set the appearance of the Button Box */
1164 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1165 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1166 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1168 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1169 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1170 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1172 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1173 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1174 g_signal_connect(G_OBJECT(button2), "clicked",
1175 G_CALLBACK(callback_delete_event),
1178 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1179 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1180 G_CALLBACK(callback_apply_description_change),
1182 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1184 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1185 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1186 g_signal_connect(G_OBJECT(button2), "clicked",
1187 G_CALLBACK(callback_do_about),
1190 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1193 gtk_widget_show_all(window);
1198 static int init_join_state(struct join_state **state)
1200 struct join_state *s;
1202 s = malloc(sizeof(struct join_state));
1207 memset(s, '\0', sizeof(struct join_state));
1214 static int initialize_join_state(struct join_state *state,
1215 const char *debug_level)
1217 struct libnetapi_ctx *ctx = NULL;
1218 NET_API_STATUS status = 0;
1220 status = libnetapi_init(&ctx);
1226 libnetapi_set_debuglevel(ctx, debug_level);
1230 char my_hostname[HOST_NAME_MAX];
1231 const char *p = NULL;
1232 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1236 state->my_fqdn = strdup(my_hostname);
1237 if (!state->my_fqdn) {
1241 p = strchr(my_hostname, '.');
1243 my_hostname[strlen(my_hostname) - strlen(p)] = '\0';
1244 state->my_hostname = strdup(my_hostname);
1245 if (!state->my_hostname) {
1249 state->my_dnsdomain = strdup(p);
1250 if (!state->my_dnsdomain) {
1257 const char *buffer = NULL;
1259 status = NetGetJoinInformation(NULL, &buffer, &type);
1263 state->name_buffer_initial = (char *)buffer;
1264 state->name_type_initial = type;
1268 struct srvsvc_NetSrvInfo1005 *info1005 = NULL;
1269 uint8_t *buffer = NULL;
1271 status = NetServerGetInfo(NULL, 1005, &buffer);
1276 info1005 = (struct srvsvc_NetSrvInfo1005 *)buffer;
1278 state->comment = strdup(info1005->comment);
1279 if (!state->comment) {
1285 struct srvsvc_NetSrvInfo100 *info100 = NULL;
1286 uint8_t *buffer = NULL;
1288 status = NetServerGetInfo(NULL, 100, &buffer);
1293 info100 = (struct srvsvc_NetSrvInfo100 *)buffer;
1295 state->comment = strdup(info100->comment);
1296 if (!state->comment) {
1307 int main(int argc, char **argv)
1309 GOptionContext *context = NULL;
1310 static const char *debug_level = NULL;
1311 struct join_state *state = NULL;
1312 GError *error = NULL;
1315 static GOptionEntry entries[] = {
1316 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1317 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1321 context = g_option_context_new("- Samba domain join utility");
1322 g_option_context_add_main_entries(context, entries, NULL);
1323 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1324 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1325 g_option_context_parse(context, &argc, &argv, &error);
1327 gtk_init(&argc, &argv);
1328 g_set_application_name("Samba");
1330 ret = init_join_state(&state);
1335 ret = initialize_join_state(state, debug_level);
1340 draw_main_window(state);