netapi: use NETSETUP join flags in examples.
[Samba.git] / source / lib / netapi / examples / netdomjoin-gui / netdomjoin-gui.c
blob970f8cf9f28b4476c2868aad8103c1fd63f07f24
1 /*
2 * Unix SMB/CIFS implementation.
3 * Join Support (gtk + netapi)
4 * Copyright (C) Guenther Deschner 2007-2008
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/>.
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <netdb.h>
29 #include <gtk/gtk.h>
30 #include <glib/gprintf.h>
32 #include <netapi.h>
34 #define MAX_CRED_LEN 256
35 #define MAX_NETBIOS_NAME_LEN 15
37 #define SAMBA_ICON_PATH "/usr/share/pixmaps/samba/samba.ico"
38 #define SAMBA_IMAGE_PATH "/usr/share/pixmaps/samba/logo.png"
39 #define SAMBA_IMAGE_PATH_SMALL "/usr/share/pixmaps/samba/logo-small.png"
41 #define NetSetupWorkgroupName ( 2 )
42 #define NetSetupDomainName ( 3 )
44 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
46 static gboolean verbose = FALSE;
48 typedef struct join_state {
49 struct libnetapi_ctx *ctx;
50 GtkWidget *window_main;
51 GtkWidget *window_parent;
52 GtkWidget *window_do_change;
53 GtkWidget *window_creds_prompt;
54 GtkWidget *entry_account;
55 GtkWidget *entry_password;
56 GtkWidget *entry_domain;
57 GtkWidget *entry_ou_list;
58 GtkWidget *entry_workgroup;
59 GtkWidget *button_ok;
60 GtkWidget *button_apply;
61 GtkWidget *button_ok_creds;
62 GtkWidget *button_get_ous;
63 GtkWidget *label_reboot;
64 GtkWidget *label_current_name_buffer;
65 GtkWidget *label_current_name_type;
66 GtkWidget *label_full_computer_name;
67 GtkWidget *label_winbind;
68 uint16_t name_type_initial;
69 uint16_t name_type_new;
70 char *name_buffer_initial;
71 char *name_buffer_new;
72 char *password;
73 char *account;
74 char *comment;
75 char *comment_new;
76 char *my_fqdn;
77 char *my_dnsdomain;
78 char *my_hostname;
79 uint16_t server_role;
80 gboolean settings_changed;
81 gboolean hostname_changed;
82 uint32_t stored_num_ous;
83 } join_state;
85 static void debug(const char *format, ...)
87 va_list args;
89 if (!verbose) {
90 return;
93 va_start(args, format);
94 g_vprintf(format, args);
95 va_end(args);
98 static gboolean callback_delete_event(GtkWidget *widget,
99 GdkEvent *event,
100 gpointer data)
102 gtk_main_quit();
103 return FALSE;
106 static void callback_do_close(GtkWidget *widget,
107 gpointer data)
109 debug("callback_do_close called\n");
111 if (data) {
112 gtk_widget_destroy(GTK_WIDGET(data));
113 data = NULL;
117 static void callback_do_freeauth(GtkWidget *widget,
118 gpointer data)
120 struct join_state *state = (struct join_state *)data;
122 debug("callback_do_freeauth called\n");
124 SAFE_FREE(state->account);
125 SAFE_FREE(state->password);
127 if (state->window_creds_prompt) {
128 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
129 state->window_creds_prompt = NULL;
133 static void callback_do_freeauth_and_close(GtkWidget *widget,
134 gpointer data)
136 struct join_state *state = (struct join_state *)data;
138 debug("callback_do_freeauth_and_close called\n");
140 SAFE_FREE(state->account);
141 SAFE_FREE(state->password);
143 if (state->window_creds_prompt) {
144 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
145 state->window_creds_prompt = NULL;
147 if (state->window_do_change) {
148 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
149 state->window_do_change = NULL;
153 static void free_join_state(struct join_state *s)
155 SAFE_FREE(s->name_buffer_initial);
156 SAFE_FREE(s->name_buffer_new);
157 SAFE_FREE(s->password);
158 SAFE_FREE(s->account);
159 SAFE_FREE(s->comment);
160 SAFE_FREE(s->comment_new);
161 SAFE_FREE(s->my_fqdn);
162 SAFE_FREE(s->my_dnsdomain);
163 SAFE_FREE(s->my_hostname);
166 static void do_cleanup(struct join_state *state)
168 libnetapi_free(state->ctx);
169 free_join_state(state);
172 static void callback_apply_description_change(GtkWidget *widget,
173 gpointer data)
175 struct join_state *state = (struct join_state *)data;
176 NET_API_STATUS status = 0;
177 uint32_t parm_err = 0;
178 struct SERVER_INFO_1005 info1005;
179 GtkWidget *dialog;
181 info1005.sv1005_comment = state->comment_new;
183 status = NetServerSetInfo(NULL, 1005, (uint8_t *)&info1005, &parm_err);
184 if (status) {
185 debug("NetServerSetInfo failed with: %s\n",
186 libnetapi_errstr(status));
187 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
188 GTK_DIALOG_DESTROY_WITH_PARENT,
189 GTK_MESSAGE_ERROR,
190 GTK_BUTTONS_OK,
191 "Failed to change computer description: %s.",
192 libnetapi_get_error_string(state->ctx, status));
193 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
195 g_signal_connect_swapped(dialog, "response",
196 G_CALLBACK(gtk_widget_destroy),
197 dialog);
199 gtk_widget_show(dialog);
200 return;
203 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
206 static void callback_do_exit(GtkWidget *widget,
207 gpointer data)
209 #if 0
210 GtkWidget *dialog;
211 gint result;
212 #endif
213 struct join_state *state = (struct join_state *)data;
215 if (!state->settings_changed) {
216 callback_delete_event(NULL, NULL, NULL);
217 return;
220 #if 0
221 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
222 GTK_DIALOG_DESTROY_WITH_PARENT,
223 GTK_MESSAGE_QUESTION,
224 GTK_BUTTONS_YES_NO,
225 "You must restart your computer before the new settings will take effect.");
226 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
227 result = gtk_dialog_run(GTK_DIALOG(dialog));
228 switch (result) {
229 case GTK_RESPONSE_YES:
230 g_print("would reboot here\n");
231 break;
232 case GTK_RESPONSE_NO:
233 default:
234 break;
236 if (dialog) {
237 gtk_widget_destroy(GTK_WIDGET(dialog));
239 #endif
240 if (state->window_main) {
241 gtk_widget_destroy(GTK_WIDGET(state->window_main));
242 state->window_main = NULL;
244 do_cleanup(state);
245 exit(0);
249 static void callback_do_reboot(GtkWidget *widget,
250 gpointer data,
251 gpointer data2)
253 GtkWidget *dialog;
254 struct join_state *state = (struct join_state *)data2;
256 debug("callback_do_reboot\n");
258 state->settings_changed = TRUE;
259 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
260 GTK_DIALOG_DESTROY_WITH_PARENT,
261 GTK_MESSAGE_INFO,
262 GTK_BUTTONS_OK,
263 "You must restart this computer for the changes to take effect.");
264 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
265 #if 0
266 g_signal_connect_swapped(dialog, "response",
267 G_CALLBACK(gtk_widget_destroy),
268 dialog);
270 debug("showing dialog\n");
271 gtk_widget_show(dialog);
272 #else
273 gtk_dialog_run(GTK_DIALOG(dialog));
274 gtk_widget_destroy(GTK_WIDGET(dialog));
275 #endif
277 gtk_label_set_text(GTK_LABEL(state->label_reboot),
278 "Changes will take effect after you restart this computer");
280 debug("destroying do_change window\n");
281 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
284 uint32_t status;
285 const char *buffer;
286 uint16_t type;
288 status = NetGetJoinInformation(NULL, &buffer, &type);
289 if (status != 0) {
290 g_print("failed to query status\n");
291 return;
294 debug("got new status: %s\n", buffer);
296 SAFE_FREE(state->name_buffer_new);
297 state->name_buffer_new = strdup(buffer);
298 state->name_type_new = type;
299 state->name_buffer_initial = strdup(buffer);
300 state->name_type_initial = type;
301 NetApiBufferFree((void *)buffer);
303 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
304 state->name_buffer_new);
305 if (state->name_type_new == NetSetupDomainName) {
306 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
307 "Domain:");
308 } else {
309 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
310 "Workgroup:");
315 static void callback_return_username(GtkWidget *widget,
316 gpointer data)
318 const gchar *entry_text;
319 struct join_state *state = (struct join_state *)data;
320 debug("callback_return_username called\n");
321 if (!widget) {
322 return;
324 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
325 if (!entry_text) {
326 return;
328 debug("callback_return_username: %s\n", entry_text);
329 SAFE_FREE(state->account);
330 state->account = strdup(entry_text);
333 static void callback_return_username_and_enter(GtkWidget *widget,
334 gpointer data)
336 const gchar *entry_text;
337 struct join_state *state = (struct join_state *)data;
338 if (!widget) {
339 return;
341 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
342 if (!entry_text) {
343 return;
345 debug("callback_return_username_and_enter: %s\n", entry_text);
346 SAFE_FREE(state->account);
347 state->account = strdup(entry_text);
348 g_signal_emit_by_name(state->button_ok_creds, "clicked");
351 static void callback_return_password(GtkWidget *widget,
352 gpointer data)
354 const gchar *entry_text;
355 struct join_state *state = (struct join_state *)data;
356 debug("callback_return_password called\n");
357 if (!widget) {
358 return;
360 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
361 if (!entry_text) {
362 return;
364 #ifdef DEBUG_PASSWORD
365 debug("callback_return_password: %s\n", entry_text);
366 #else
367 debug("callback_return_password: (not printed)\n");
368 #endif
369 SAFE_FREE(state->password);
370 state->password = strdup(entry_text);
373 static void callback_return_password_and_enter(GtkWidget *widget,
374 gpointer data)
376 const gchar *entry_text;
377 struct join_state *state = (struct join_state *)data;
378 if (!widget) {
379 return;
381 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
382 if (!entry_text) {
383 return;
385 #ifdef DEBUG_PASSWORD
386 debug("callback_return_password_and_enter: %s\n", entry_text);
387 #else
388 debug("callback_return_password_and_enter: (not printed)\n");
389 #endif
390 SAFE_FREE(state->password);
391 state->password = strdup(entry_text);
392 g_signal_emit_by_name(state->button_ok_creds, "clicked");
395 static void callback_do_storeauth(GtkWidget *widget,
396 gpointer data)
398 struct join_state *state = (struct join_state *)data;
400 debug("callback_do_storeauth called\n");
402 SAFE_FREE(state->account);
403 SAFE_FREE(state->password);
405 callback_return_username(state->entry_account, (gpointer)state);
406 callback_return_password(state->entry_password, (gpointer)state);
408 if (state->window_creds_prompt) {
409 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
410 state->window_creds_prompt = NULL;
414 static void callback_continue(GtkWidget *widget,
415 gpointer data)
417 struct join_state *state = (struct join_state *)data;
419 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
420 g_signal_emit_by_name(state->button_ok, "clicked");
423 static void callback_do_storeauth_and_continue(GtkWidget *widget,
424 gpointer data)
426 callback_do_storeauth(widget, data);
427 callback_continue(NULL, data);
430 static void callback_do_storeauth_and_scan(GtkWidget *widget,
431 gpointer data)
433 struct join_state *state = (struct join_state *)data;
434 callback_do_storeauth(widget, data);
435 g_signal_emit_by_name(state->button_get_ous, "clicked");
438 static void callback_do_hostname_change(GtkWidget *widget,
439 gpointer data)
441 GtkWidget *dialog;
442 const char *str = NULL;
444 struct join_state *state = (struct join_state *)data;
446 switch (state->name_type_initial) {
447 case NetSetupDomainName:
448 str = "To be implemented: call NetRenameMachineInDomain\n";
449 break;
450 case NetSetupWorkgroupName:
451 str = "To be implemented: call SetComputerNameEx\n";
452 break;
453 default:
454 break;
457 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
458 GTK_DIALOG_DESTROY_WITH_PARENT,
459 GTK_MESSAGE_ERROR,
460 GTK_BUTTONS_CLOSE,
461 str);
463 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
464 g_signal_connect_swapped(dialog, "response",
465 G_CALLBACK(gtk_widget_destroy),
466 dialog);
467 gtk_widget_show(dialog);
470 static void callback_creds_prompt(GtkWidget *widget,
471 gpointer data,
472 const char *label_string,
473 gpointer cont_fn)
475 GtkWidget *window;
476 GtkWidget *box1;
477 GtkWidget *bbox;
478 GtkWidget *button;
479 GtkWidget *label;
481 struct join_state *state = (struct join_state *)data;
483 debug("callback_creds_prompt\n");
485 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
486 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
488 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
489 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
490 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
491 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
492 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
494 g_signal_connect(G_OBJECT(window), "delete_event",
495 G_CALLBACK(callback_do_close), window);
497 state->window_creds_prompt = window;
498 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
500 box1 = gtk_vbox_new(FALSE, 0);
502 gtk_container_add(GTK_CONTAINER(window), box1);
504 label = gtk_label_new(label_string);
505 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
506 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
508 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
510 gtk_widget_show(label);
512 /* USER NAME */
513 label = gtk_label_new("User name:");
514 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
515 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
516 gtk_widget_show(label);
518 state->entry_account = gtk_entry_new();
519 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
520 g_signal_connect(G_OBJECT(state->entry_account), "activate",
521 G_CALLBACK(callback_return_username_and_enter),
522 (gpointer)state);
523 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
524 0, GTK_ENTRY(state->entry_account)->text_length);
525 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
526 gtk_widget_show(state->entry_account);
528 /* PASSWORD */
529 label = gtk_label_new("Password:");
530 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
531 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
532 gtk_widget_show(label);
534 state->entry_password = gtk_entry_new();
535 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
536 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
537 g_signal_connect(G_OBJECT(state->entry_password), "activate",
538 G_CALLBACK(callback_return_password_and_enter),
539 (gpointer)state);
540 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
541 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
542 0, GTK_ENTRY(state->entry_password)->text_length);
543 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
544 gtk_widget_show(state->entry_password);
546 /* BUTTONS */
547 bbox = gtk_hbutton_box_new();
548 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
549 gtk_container_add(GTK_CONTAINER(box1), bbox);
550 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
551 gtk_box_set_spacing(GTK_BOX(bbox), 10);
553 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
554 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
555 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
556 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
557 G_CALLBACK(cont_fn),
558 (gpointer)state);
559 gtk_widget_show(state->button_ok_creds);
561 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
562 gtk_container_add(GTK_CONTAINER(bbox), button);
563 g_signal_connect(G_OBJECT(button), "clicked",
564 G_CALLBACK(callback_do_freeauth),
565 (gpointer)state);
566 gtk_widget_show_all(window);
569 static void callback_do_join(GtkWidget *widget,
570 gpointer data)
572 GtkWidget *dialog;
574 NET_API_STATUS status;
575 const char *err_str = NULL;
576 uint32_t join_flags = 0;
577 uint32_t unjoin_flags = 0;
578 gboolean domain_join = FALSE;
579 gboolean try_unjoin = FALSE;
580 gboolean join_creds_required = TRUE;
581 gboolean unjoin_creds_required = TRUE;
582 const char *new_workgroup_type = NULL;
583 const char *initial_workgroup_type = NULL;
584 const char *account_ou = NULL;
586 struct join_state *state = (struct join_state *)data;
588 if (state->hostname_changed) {
589 callback_do_hostname_change(NULL, state);
590 return;
593 switch (state->name_type_initial) {
594 case NetSetupWorkgroupName:
595 initial_workgroup_type = "workgroup";
596 break;
597 case NetSetupDomainName:
598 initial_workgroup_type = "domain";
599 break;
600 default:
601 break;
604 switch (state->name_type_new) {
605 case NetSetupWorkgroupName:
606 new_workgroup_type = "workgroup";
607 break;
608 case NetSetupDomainName:
609 new_workgroup_type = "domain";
610 break;
611 default:
612 break;
615 account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
616 if (account_ou && strlen(account_ou) == 0) {
617 account_ou = NULL;
620 if ((state->name_type_initial != NetSetupDomainName) &&
621 (state->name_type_new != NetSetupDomainName)) {
622 join_creds_required = FALSE;
623 unjoin_creds_required = FALSE;
626 if (state->name_type_new == NetSetupDomainName) {
627 domain_join = TRUE;
628 join_creds_required = TRUE;
629 join_flags = NETSETUP_JOIN_DOMAIN |
630 NETSETUP_ACCT_CREATE |
631 NETSETUP_DOMAIN_JOIN_IF_JOINED; /* for testing */
634 if ((state->name_type_initial == NetSetupDomainName) &&
635 (state->name_type_new == NetSetupWorkgroupName)) {
636 try_unjoin = TRUE;
637 unjoin_creds_required = TRUE;
638 join_creds_required = FALSE;
639 unjoin_flags = NETSETUP_JOIN_DOMAIN |
640 NETSETUP_ACCT_DELETE;
643 if (try_unjoin) {
645 debug("callback_do_join: Unjoining\n");
647 if (unjoin_creds_required) {
648 if (!state->account || !state->password) {
649 debug("callback_do_join: no creds yet\n");
650 callback_creds_prompt(NULL, state,
651 "Enter the name and password of an account with permission to leave the domain.",
652 callback_do_storeauth_and_continue);
655 if (!state->account || !state->password) {
656 debug("callback_do_join: still no creds???\n");
657 return;
661 status = NetUnjoinDomain(NULL,
662 state->account,
663 state->password,
664 unjoin_flags);
665 if (status != 0) {
666 callback_do_freeauth(NULL, state);
667 err_str = libnetapi_get_error_string(state->ctx, status);
668 g_print("callback_do_join: failed to unjoin (%s)\n",
669 err_str);
670 #if 0
672 /* in fact we shouldn't annoy the user with an error message here */
674 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
675 GTK_DIALOG_DESTROY_WITH_PARENT,
676 GTK_MESSAGE_ERROR,
677 GTK_BUTTONS_CLOSE,
678 "The following error occured attempting to unjoin the %s: \"%s\": %s",
679 initial_workgroup_type,
680 state->name_buffer_initial,
681 err_str);
682 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
683 gtk_dialog_run(GTK_DIALOG(dialog));
684 gtk_widget_destroy(dialog);
685 #endif
690 /* before prompting for creds, make sure we can find a dc */
692 if (domain_join) {
694 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
696 status = DsGetDcName(NULL,
697 state->name_buffer_new,
698 NULL,
699 NULL,
701 &dc_info);
702 if (status != 0) {
703 err_str = libnetapi_get_error_string(state->ctx, status);
704 g_print("callback_do_join: failed find dc (%s)\n", err_str);
706 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
707 GTK_DIALOG_DESTROY_WITH_PARENT,
708 GTK_MESSAGE_ERROR,
709 GTK_BUTTONS_CLOSE,
710 "Failed to find a domain controller for domain: \"%s\": %s",
711 state->name_buffer_new,
712 err_str);
714 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
715 g_signal_connect_swapped(dialog, "response",
716 G_CALLBACK(gtk_widget_destroy),
717 dialog);
719 gtk_widget_show(dialog);
721 return;
725 if (join_creds_required) {
726 if (!state->account || !state->password) {
727 debug("callback_do_join: no creds yet\n");
728 callback_creds_prompt(NULL, state,
729 "Enter the name and password of an account with permission to leave the domain.",
730 callback_do_storeauth_and_continue);
733 if (!state->account || !state->password) {
734 debug("callback_do_join: still no creds???\n");
735 return;
739 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
740 new_workgroup_type,
741 state->name_buffer_new,
742 join_flags);
743 if (domain_join) {
744 debug("as %s ", state->account);
745 #ifdef DEBUG_PASSWORD
746 debug("with %s ", state->password);
747 #endif
749 debug("\n");
751 status = NetJoinDomain(NULL,
752 state->name_buffer_new,
753 account_ou,
754 state->account,
755 state->password,
756 join_flags);
757 if (status != 0) {
758 callback_do_freeauth(NULL, state);
759 err_str = libnetapi_get_error_string(state->ctx, status);
760 g_print("callback_do_join: failed to join (%s)\n", err_str);
762 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
763 GTK_DIALOG_DESTROY_WITH_PARENT,
764 GTK_MESSAGE_ERROR,
765 GTK_BUTTONS_CLOSE,
766 "The following error occured attempting to join the %s: \"%s\": %s",
767 new_workgroup_type,
768 state->name_buffer_new,
769 err_str);
771 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
772 g_signal_connect_swapped(dialog, "response",
773 G_CALLBACK(gtk_widget_destroy),
774 dialog);
776 gtk_widget_show(dialog);
778 return;
781 debug("callback_do_join: Successfully joined %s\n",
782 new_workgroup_type);
784 callback_do_freeauth(NULL, state);
785 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
786 GTK_DIALOG_DESTROY_WITH_PARENT,
787 GTK_MESSAGE_INFO,
788 GTK_BUTTONS_OK,
789 "Welcome to the %s %s.",
790 state->name_buffer_new,
791 new_workgroup_type);
793 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
794 gtk_dialog_run(GTK_DIALOG(dialog));
795 gtk_widget_destroy(dialog);
797 callback_do_reboot(NULL, state->window_parent, state);
800 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
801 gpointer data)
803 const gchar *entry_text = NULL;
804 char *str = NULL;
805 struct join_state *state = (struct join_state *)data;
807 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
808 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
809 if (!entry_text || entry_text[0] == 0) {
810 state->hostname_changed = FALSE;
811 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
812 return;
814 if (strcasecmp(state->my_hostname, entry_text) == 0) {
815 state->hostname_changed = FALSE;
816 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
817 return;
819 state->hostname_changed = TRUE;
820 if (state->name_type_initial == NetSetupDomainName) {
821 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
822 } else {
823 asprintf(&str, "%s.", entry_text);
825 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
826 free(str);
828 if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
829 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
833 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
834 gpointer data)
836 const gchar *entry_text = NULL;
837 struct join_state *state = (struct join_state *)data;
838 int string_unchanged = 0;
840 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
841 debug("callback_enter_computer_description_and_unlock: %s\n",
842 entry_text);
843 #if 0
844 if (!entry_text || entry_text[0] == 0) {
845 string_unchanged = 1;
846 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
847 FALSE);
848 return;
850 #endif
851 if (entry_text && strcasecmp(state->comment, entry_text) == 0) {
852 string_unchanged = 1;
853 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
854 FALSE);
855 return;
858 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
859 SAFE_FREE(state->comment_new);
860 state->comment_new = strdup(entry_text);
865 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
866 gpointer data)
868 const gchar *entry_text = NULL;
869 struct join_state *state = (struct join_state *)data;
871 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
872 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
873 if (!entry_text || entry_text[0] == 0) {
874 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
875 return;
877 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
878 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
879 return;
881 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
882 SAFE_FREE(state->name_buffer_new);
883 state->name_buffer_new = strdup(entry_text);
884 state->name_type_new = NetSetupWorkgroupName;
887 static void callback_enter_domain_and_unlock(GtkWidget *widget,
888 gpointer data)
890 const gchar *entry_text = NULL;
891 struct join_state *state = (struct join_state *)data;
893 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
894 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
895 if (!entry_text || entry_text[0] == 0) {
896 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
897 return;
899 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
900 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
901 return;
903 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
904 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
905 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
906 SAFE_FREE(state->name_buffer_new);
907 state->name_buffer_new = strdup(entry_text);
908 state->name_type_new = NetSetupDomainName;
911 static void callback_apply_continue(GtkWidget *widget,
912 gpointer data)
914 struct join_state *state = (struct join_state *)data;
916 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
917 g_signal_emit_by_name(state->button_apply, "clicked");
920 static void callback_do_join_workgroup(GtkWidget *widget,
921 gpointer data)
923 struct join_state *state = (struct join_state *)data;
924 debug("callback_do_join_workgroup choosen\n");
925 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
926 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
927 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
928 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
929 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
930 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
933 static void callback_do_join_domain(GtkWidget *widget,
934 gpointer data)
936 struct join_state *state = (struct join_state *)data;
937 debug("callback_do_join_domain choosen\n");
938 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
939 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
940 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
941 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
944 static void callback_do_getous(GtkWidget *widget,
945 gpointer data)
947 NET_API_STATUS status;
948 uint32_t num_ous = 0;
949 const char **ous = NULL;
950 int i;
951 const char *domain = NULL;
952 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
953 const char *err_str = NULL;
954 GtkWidget *dialog;
956 struct join_state *state = (struct join_state *)data;
958 debug("callback_do_getous called\n");
960 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
962 status = DsGetDcName(NULL,
963 domain,
964 NULL,
965 NULL,
967 &dc_info);
968 if (status != 0) {
969 err_str = libnetapi_get_error_string(state->ctx, status);
970 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
972 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
973 GTK_DIALOG_DESTROY_WITH_PARENT,
974 GTK_MESSAGE_ERROR,
975 GTK_BUTTONS_CLOSE,
976 "Failed to find a domain controller for domain: \"%s\": %s",
977 domain,
978 err_str);
980 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
981 g_signal_connect_swapped(dialog, "response",
982 G_CALLBACK(gtk_widget_destroy),
983 dialog);
985 gtk_widget_show(dialog);
987 return;
990 if (!state->account || !state->password) {
991 debug("callback_do_getous: no creds yet\n");
992 callback_creds_prompt(NULL, state,
993 "Enter the name and password of an account with permission to join the domain.",
994 callback_do_storeauth_and_scan);
997 if (!state->account || !state->password) {
998 debug("callback_do_getous: still no creds ???\n");
999 return;
1002 status = NetGetJoinableOUs(NULL, domain,
1003 state->account,
1004 state->password,
1005 &num_ous, &ous);
1006 if (status != NET_API_STATUS_SUCCESS) {
1007 callback_do_freeauth(NULL, state);
1008 debug("failed to call NetGetJoinableOUs: %s\n",
1009 libnetapi_get_error_string(state->ctx, status));
1010 dialog = gtk_message_dialog_new(NULL,
1011 GTK_DIALOG_DESTROY_WITH_PARENT,
1012 GTK_MESSAGE_INFO,
1013 GTK_BUTTONS_OK,
1014 "Failed to query joinable OUs: %s",
1015 libnetapi_get_error_string(state->ctx, status));
1016 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1017 gtk_dialog_run(GTK_DIALOG(dialog));
1018 gtk_widget_destroy(dialog);
1019 return;
1022 for (i=0; i<state->stored_num_ous; i++) {
1023 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1025 for (i=0; i<num_ous && ous[i] != NULL; i++) {
1026 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1027 ous[i]);
1029 NetApiBufferFree(ous);
1030 state->stored_num_ous = num_ous;
1031 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1034 static void callback_do_change(GtkWidget *widget,
1035 gpointer data)
1037 GtkWidget *window;
1038 GtkWidget *box1;
1039 GtkWidget *bbox;
1040 GtkWidget *button_workgroup;
1041 GtkWidget *button_domain;
1042 GtkWidget *button;
1043 GtkWidget *label;
1044 GtkWidget *frame_horz;
1045 GtkWidget *vbox;
1046 GtkWidget *entry;
1047 GSList *group;
1049 struct join_state *state = (struct join_state *)data;
1051 debug("callback_do_change called\n");
1053 #if 0
1054 /* FIXME: add proper warnings for Samba as a DC */
1055 if (state->server_role == 3) {
1056 GtkWidget *dialog;
1057 callback_do_freeauth(NULL, state);
1058 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1059 GTK_DIALOG_DESTROY_WITH_PARENT,
1060 GTK_MESSAGE_ERROR,
1061 GTK_BUTTONS_OK,
1062 "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.");
1063 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1064 g_signal_connect_swapped(dialog, "response",
1065 G_CALLBACK(gtk_widget_destroy),
1066 dialog);
1068 gtk_widget_show(dialog);
1069 return;
1071 #endif
1073 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1074 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1075 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1076 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1078 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1079 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1080 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1081 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1083 g_signal_connect(G_OBJECT(window), "delete_event",
1084 G_CALLBACK(callback_do_close), window);
1086 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1088 box1 = gtk_vbox_new(FALSE, 0);
1089 gtk_container_add(GTK_CONTAINER(window), box1);
1091 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1092 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1093 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1094 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1095 gtk_widget_show(label);
1097 /* COMPUTER NAME */
1098 label = gtk_label_new("Computer name:");
1099 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1100 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1101 gtk_widget_show(label);
1103 state->label_full_computer_name = gtk_label_new(NULL);
1105 entry = gtk_entry_new();
1106 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1107 g_signal_connect(G_OBJECT(entry), "changed",
1108 G_CALLBACK(callback_enter_hostname_and_unlock),
1109 (gpointer)state);
1110 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1111 gtk_editable_select_region(GTK_EDITABLE(entry),
1112 0, GTK_ENTRY(entry)->text_length);
1114 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1115 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1116 gtk_widget_show(entry);
1119 /* FULL COMPUTER NAME */
1120 label = gtk_label_new("Full computer name:");
1121 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1122 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1123 gtk_widget_show(label);
1126 const gchar *entry_text;
1127 char *str = NULL;
1128 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1129 if (state->name_type_initial == NetSetupDomainName) {
1130 asprintf(&str, "%s.%s", entry_text,
1131 state->my_dnsdomain);
1132 } else {
1133 asprintf(&str, "%s.", entry_text);
1135 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1136 str);
1137 free(str);
1138 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1139 gtk_box_pack_start(GTK_BOX(box1),
1140 state->label_full_computer_name, TRUE, TRUE, 0);
1141 gtk_widget_show(state->label_full_computer_name);
1144 /* BOX */
1145 frame_horz = gtk_frame_new ("Member Of");
1146 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1148 vbox = gtk_vbox_new(FALSE, 0);
1149 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1150 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1152 /* TWO ENTRIES */
1153 state->entry_workgroup = gtk_entry_new();
1154 state->entry_domain = gtk_entry_new();
1156 /* DOMAIN */
1157 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1158 if (state->name_type_initial == NetSetupDomainName) {
1159 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1161 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1162 g_signal_connect(G_OBJECT(button_domain), "clicked",
1163 G_CALLBACK(callback_do_join_domain),
1164 (gpointer)state);
1167 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1168 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1169 G_CALLBACK(callback_enter_domain_and_unlock),
1170 (gpointer)state);
1171 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1172 G_CALLBACK(callback_continue),
1173 (gpointer)state);
1174 if (state->name_type_initial == NetSetupDomainName) {
1175 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1176 state->name_buffer_initial);
1177 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1178 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1180 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1181 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1182 gtk_widget_show(state->entry_domain);
1184 gtk_widget_show(button_domain);
1186 /* WORKGROUP */
1187 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1188 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1189 if (state->name_type_initial == NetSetupWorkgroupName) {
1190 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1192 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1193 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1194 G_CALLBACK(callback_do_join_workgroup),
1195 (gpointer)state);
1197 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1198 MAX_NETBIOS_NAME_LEN);
1199 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1200 G_CALLBACK(callback_enter_workgroup_and_unlock),
1201 (gpointer)state);
1202 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1203 G_CALLBACK(callback_continue),
1204 (gpointer)state);
1206 if (state->name_type_initial == NetSetupWorkgroupName) {
1207 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1208 state->name_buffer_initial);
1209 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1210 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1212 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1213 gtk_widget_show(state->entry_workgroup);
1215 gtk_widget_show(button_workgroup);
1217 /* Advanced Options */
1218 frame_horz = gtk_frame_new("Advanced Options");
1219 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1221 vbox = gtk_vbox_new(FALSE, 0);
1222 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1223 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1225 /* OUs */
1226 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1227 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1228 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1229 G_CALLBACK(callback_do_getous),
1230 (gpointer)state);
1232 state->entry_ou_list = gtk_combo_box_entry_new_text();
1233 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1234 if (state->name_type_initial == NetSetupWorkgroupName) {
1235 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1236 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1238 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1239 gtk_widget_show(state->entry_ou_list);
1242 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1243 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1244 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1248 /* BUTTONS */
1249 bbox = gtk_hbutton_box_new();
1250 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1251 gtk_container_add(GTK_CONTAINER(box1), bbox);
1252 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1253 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1255 state->window_do_change = window;
1256 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1257 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1258 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1259 G_CALLBACK(callback_do_join),
1260 (gpointer)state);
1262 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1263 gtk_container_add(GTK_CONTAINER(bbox), button);
1264 g_signal_connect(G_OBJECT(button), "clicked",
1265 G_CALLBACK(callback_do_freeauth_and_close),
1266 (gpointer)state);
1268 gtk_widget_show_all(window);
1271 static void callback_do_about(GtkWidget *widget,
1272 gpointer data)
1274 GdkPixbuf *logo;
1275 GError *error = NULL;
1276 GtkWidget *about;
1278 debug("callback_do_about called\n");
1280 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1281 &error);
1282 if (logo == NULL) {
1283 g_print("failed to load logo from %s: %s\n",
1284 SAMBA_IMAGE_PATH, error->message);
1287 about = gtk_about_dialog_new();
1288 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1289 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1290 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1291 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1292 "Copyright Günther Deschner 2007-2008");
1293 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1294 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1295 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1296 if (logo) {
1297 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1299 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1300 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1301 g_signal_connect_swapped(about, "response",
1302 G_CALLBACK(gtk_widget_destroy),
1303 about);
1305 gtk_widget_show(about);
1308 static int draw_main_window(struct join_state *state)
1310 GtkWidget *window;
1311 GtkWidget *button;
1312 GtkWidget *label;
1313 GtkWidget *main_vbox;
1314 GtkWidget *vbox;
1315 GtkWidget *hbox;
1316 GtkWidget *bbox;
1317 GtkWidget *image;
1318 GtkWidget *table;
1319 GtkWidget *entry;
1320 GdkPixbuf *icon;
1321 GError *error = NULL;
1323 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1324 &error);
1325 if (icon == NULL) {
1326 g_print("failed to load icon from %s : %s\n",
1327 SAMBA_ICON_PATH, error->message);
1330 #if 1
1331 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1332 #else
1333 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1334 #endif
1335 if (image == NULL) {
1336 g_print("failed to load logo from %s : %s\n",
1337 SAMBA_IMAGE_PATH_SMALL, error->message);
1340 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1341 state->window_main = window;
1343 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1344 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1345 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1346 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1348 g_signal_connect(G_OBJECT(window), "delete_event",
1349 G_CALLBACK(callback_delete_event), NULL);
1351 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1353 main_vbox = gtk_vbox_new(FALSE, 10);
1354 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1356 #if 0
1357 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1358 gtk_widget_show(image);
1359 #endif
1360 /* Hbox */
1361 hbox = gtk_hbox_new(FALSE, 10);
1362 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1365 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1366 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1367 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1368 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1369 gtk_widget_show(image);
1371 /* Label */
1372 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1373 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1374 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1375 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1376 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1377 gtk_widget_show(label);
1380 gtk_widget_show(hbox);
1382 vbox = gtk_vbox_new(FALSE, 0);
1383 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1384 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1386 /* Table */
1387 table = gtk_table_new(6, 3, TRUE);
1388 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1389 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1390 gtk_container_add(GTK_CONTAINER(vbox), table);
1393 /* Label */
1394 label = gtk_label_new("Computer description:");
1395 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1396 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1397 gtk_widget_show(label);
1399 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1401 /* Entry */
1402 entry = gtk_entry_new();
1403 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1404 g_signal_connect(G_OBJECT(entry), "changed",
1405 G_CALLBACK(callback_enter_computer_description_and_unlock),
1406 state);
1407 g_signal_connect(G_OBJECT(entry), "activate",
1408 G_CALLBACK(callback_apply_continue),
1409 (gpointer)state);
1411 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1412 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1413 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1414 gtk_widget_show(entry);
1417 /* Label */
1418 label = gtk_label_new("For example: \"Samba \%v\".");
1419 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1420 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1421 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1422 gtk_widget_show(label);
1424 /* Label */
1425 label = gtk_label_new("Full computer name:");
1426 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1427 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1428 gtk_widget_show(label);
1431 /* Label */
1432 char *str = NULL;
1433 if (state->name_type_initial == NetSetupDomainName) {
1434 asprintf(&str, "%s.%s", state->my_hostname,
1435 state->my_dnsdomain);
1436 } else {
1437 asprintf(&str, "%s.", state->my_hostname);
1440 label = gtk_label_new(str);
1441 SAFE_FREE(str);
1442 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1443 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1444 gtk_widget_show(label);
1447 /* Label */
1448 if (state->name_type_initial == NetSetupDomainName) {
1449 label = gtk_label_new("Domain:");
1450 } else {
1451 label = gtk_label_new("Workgroup:");
1453 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1454 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1455 gtk_widget_show(label);
1456 state->label_current_name_type = label;
1458 /* Label */
1459 label = gtk_label_new(state->name_buffer_initial);
1460 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1461 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1462 gtk_widget_show(label);
1463 state->label_current_name_buffer = label;
1466 hbox = gtk_hbox_new(FALSE, 0);
1467 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1468 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1469 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1474 /* bbox */
1475 bbox = gtk_hbutton_box_new();
1476 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1477 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1478 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1479 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1481 button = gtk_button_new_with_mnemonic("Ch_ange");
1482 g_signal_connect(G_OBJECT(button), "clicked",
1483 G_CALLBACK(callback_do_change),
1484 (gpointer)state);
1485 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1486 gtk_widget_show(button);
1488 /* Label (hidden) */
1489 state->label_reboot = gtk_label_new(NULL);
1490 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1491 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1492 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1493 gtk_widget_show(state->label_reboot);
1495 #if 0
1496 gtk_box_pack_start(GTK_BOX(vbox),
1497 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1498 TRUE, TRUE, 5);
1499 #endif
1502 GtkWidget *frame;
1503 GtkWidget *bbox2;
1504 GtkWidget *button2;
1506 frame = gtk_frame_new(NULL);
1507 bbox2 = gtk_hbutton_box_new();
1509 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1510 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1512 /* Set the appearance of the Button Box */
1513 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1514 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1515 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1517 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1518 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1519 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1521 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1522 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1523 g_signal_connect(G_OBJECT(button2), "clicked",
1524 G_CALLBACK(callback_delete_event),
1525 window);
1527 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1528 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1529 G_CALLBACK(callback_apply_description_change),
1530 state);
1531 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1533 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1534 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1535 g_signal_connect(G_OBJECT(button2), "clicked",
1536 G_CALLBACK(callback_do_about),
1537 window);
1538 #if 0
1539 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1540 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1541 g_signal_connect(G_OBJECT(button2), "clicked",
1542 G_CALLBACK(callback_do_about),
1543 window);
1544 #endif
1545 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1548 gtk_widget_show_all(window);
1550 return 0;
1553 static int init_join_state(struct join_state **state)
1555 struct join_state *s;
1557 s = (struct join_state *)malloc(sizeof(struct join_state));
1558 if (!s) {
1559 return -1;
1562 memset(s, '\0', sizeof(struct join_state));
1564 *state = s;
1566 return 0;
1569 static int initialize_join_state(struct join_state *state,
1570 const char *debug_level)
1572 struct libnetapi_ctx *ctx = NULL;
1573 NET_API_STATUS status = 0;
1575 status = libnetapi_init(&ctx);
1576 if (status) {
1577 return status;
1580 if (debug_level) {
1581 libnetapi_set_debuglevel(ctx, debug_level);
1585 char my_hostname[HOST_NAME_MAX];
1586 const char *p = NULL;
1587 struct hostent *hp = NULL;
1589 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1590 return -1;
1593 p = strchr(my_hostname, '.');
1594 if (p) {
1595 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1597 state->my_hostname = strdup(my_hostname);
1598 if (!state->my_hostname) {
1599 return -1;
1601 debug("state->my_hostname: %s\n", state->my_hostname);
1603 hp = gethostbyname(my_hostname);
1604 if (!hp || !hp->h_name || !*hp->h_name) {
1605 return -1;
1608 state->my_fqdn = strdup(hp->h_name);
1609 if (!state->my_fqdn) {
1610 return -1;
1612 debug("state->my_fqdn: %s\n", state->my_fqdn);
1614 p = strchr(state->my_fqdn, '.');
1615 if (p) {
1616 p++;
1617 state->my_dnsdomain = strdup(p);
1618 } else {
1619 state->my_dnsdomain = strdup("");
1621 if (!state->my_dnsdomain) {
1622 return -1;
1624 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1628 const char *buffer = NULL;
1629 uint16_t type = 0;
1630 status = NetGetJoinInformation(NULL, &buffer, &type);
1631 if (status != 0) {
1632 printf("NetGetJoinInformation failed with: %s\n",
1633 libnetapi_get_error_string(state->ctx, status));
1634 return status;
1636 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1637 state->name_buffer_initial = strdup(buffer);
1638 if (!state->name_buffer_initial) {
1639 return -1;
1641 state->name_type_initial = type;
1642 NetApiBufferFree((void *)buffer);
1646 struct SERVER_INFO_1005 *info1005 = NULL;
1647 uint8_t *buffer = NULL;
1649 status = NetServerGetInfo(NULL, 1005, &buffer);
1650 if (status != 0) {
1651 printf("NetServerGetInfo failed with: %s\n",
1652 libnetapi_get_error_string(state->ctx, status));
1653 return status;
1656 info1005 = (struct SERVER_INFO_1005 *)buffer;
1658 state->comment = strdup(info1005->sv1005_comment);
1659 if (!state->comment) {
1660 return -1;
1662 NetApiBufferFree(buffer);
1664 #if 0
1666 struct srvsvc_NetSrvInfo100 *info100 = NULL;
1667 uint8_t *buffer = NULL;
1669 status = NetServerGetInfo(NULL, 100, &buffer);
1670 if (status) {
1671 return status;
1674 info100 = (struct srvsvc_NetSrvInfo100 *)buffer;
1676 state->comment = strdup(info100->comment);
1677 if (!state->comment) {
1678 return -1;
1681 #endif
1683 state->ctx = ctx;
1685 return 0;
1688 int main(int argc, char **argv)
1690 GOptionContext *context = NULL;
1691 static const char *debug_level = NULL;
1692 struct join_state *state = NULL;
1693 GError *error = NULL;
1694 int ret = 0;
1696 static GOptionEntry entries[] = {
1697 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1698 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1699 { NULL }
1702 context = g_option_context_new("- Samba domain join utility");
1703 g_option_context_add_main_entries(context, entries, NULL);
1704 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1705 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1706 g_option_context_parse(context, &argc, &argv, &error);
1708 gtk_init(&argc, &argv);
1709 g_set_application_name("Samba");
1711 ret = init_join_state(&state);
1712 if (ret) {
1713 return ret;
1716 ret = initialize_join_state(state, debug_level);
1717 if (ret) {
1718 return ret;
1721 draw_main_window(state);
1723 gtk_main();
1725 do_cleanup(state);
1727 return 0;