netdomjoin-gui: fix more gtk runtime warnings.
[Samba.git] / source / lib / netapi / examples / netdomjoin-gui / netdomjoin-gui.c
blob1da8169f6338b9b92dbb98418fbce2aa5a2a14b1
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 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
42 #define WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE ( 0x00000004 )
43 #define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
44 #define WKSSVC_JOIN_FLAGS_JOIN_TYPE ( 0x00000001 )
46 #define NetSetupWorkgroupName ( 2 )
47 #define NetSetupDomainName ( 3 )
49 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
51 static gboolean verbose = FALSE;
53 typedef struct join_state {
54 struct libnetapi_ctx *ctx;
55 GtkWidget *window_main;
56 GtkWidget *window_parent;
57 GtkWidget *window_do_change;
58 GtkWidget *window_creds_prompt;
59 GtkWidget *entry_account;
60 GtkWidget *entry_password;
61 GtkWidget *entry_domain;
62 GtkWidget *entry_ou_list;
63 GtkWidget *entry_workgroup;
64 GtkWidget *button_ok;
65 GtkWidget *button_apply;
66 GtkWidget *button_ok_creds;
67 GtkWidget *button_get_ous;
68 GtkWidget *label_reboot;
69 GtkWidget *label_current_name_buffer;
70 GtkWidget *label_current_name_type;
71 GtkWidget *label_full_computer_name;
72 GtkWidget *label_winbind;
73 uint16_t name_type_initial;
74 uint16_t name_type_new;
75 char *name_buffer_initial;
76 char *name_buffer_new;
77 char *password;
78 char *account;
79 char *comment;
80 char *comment_new;
81 char *my_fqdn;
82 char *my_dnsdomain;
83 char *my_hostname;
84 uint16_t server_role;
85 gboolean settings_changed;
86 gboolean hostname_changed;
87 uint32_t stored_num_ous;
88 } join_state;
90 static void debug(const char *format, ...)
92 va_list args;
94 if (!verbose) {
95 return;
98 va_start(args, format);
99 g_vprintf(format, args);
100 va_end(args);
103 static gboolean callback_delete_event(GtkWidget *widget,
104 GdkEvent *event,
105 gpointer data)
107 gtk_main_quit();
108 return FALSE;
111 static void callback_do_close(GtkWidget *widget,
112 gpointer data)
114 debug("callback_do_close called\n");
116 if (data) {
117 gtk_widget_destroy(GTK_WIDGET(data));
118 data = NULL;
122 static void callback_do_freeauth(GtkWidget *widget,
123 gpointer data)
125 struct join_state *state = (struct join_state *)data;
127 debug("callback_do_freeauth called\n");
129 SAFE_FREE(state->account);
130 SAFE_FREE(state->password);
132 if (state->window_creds_prompt) {
133 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
134 state->window_creds_prompt = NULL;
138 static void callback_do_freeauth_and_close(GtkWidget *widget,
139 gpointer data)
141 struct join_state *state = (struct join_state *)data;
143 debug("callback_do_freeauth_and_close called\n");
145 SAFE_FREE(state->account);
146 SAFE_FREE(state->password);
148 if (state->window_creds_prompt) {
149 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
150 state->window_creds_prompt = NULL;
152 if (state->window_do_change) {
153 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
154 state->window_do_change = NULL;
158 static void free_join_state(struct join_state *s)
160 SAFE_FREE(s->name_buffer_initial);
161 SAFE_FREE(s->name_buffer_new);
162 SAFE_FREE(s->password);
163 SAFE_FREE(s->account);
164 SAFE_FREE(s->comment);
165 SAFE_FREE(s->comment_new);
166 SAFE_FREE(s->my_fqdn);
167 SAFE_FREE(s->my_dnsdomain);
168 SAFE_FREE(s->my_hostname);
171 static void do_cleanup(struct join_state *state)
173 libnetapi_free(state->ctx);
174 free_join_state(state);
177 static void callback_apply_description_change(GtkWidget *widget,
178 gpointer data)
180 struct join_state *state = (struct join_state *)data;
181 NET_API_STATUS status = 0;
182 uint32_t parm_err = 0;
183 struct SERVER_INFO_1005 info1005;
184 GtkWidget *dialog;
186 info1005.sv1005_comment = state->comment_new;
188 status = NetServerSetInfo(NULL, 1005, (uint8_t *)&info1005, &parm_err);
189 if (status) {
190 debug("NetServerSetInfo failed with: %s\n",
191 libnetapi_errstr(status));
192 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
193 GTK_DIALOG_DESTROY_WITH_PARENT,
194 GTK_MESSAGE_ERROR,
195 GTK_BUTTONS_OK,
196 "Failed to change computer description: %s.",
197 libnetapi_get_error_string(state->ctx, status));
198 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
200 g_signal_connect_swapped(dialog, "response",
201 G_CALLBACK(gtk_widget_destroy),
202 dialog);
204 gtk_widget_show(dialog);
205 return;
208 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
211 static void callback_do_exit(GtkWidget *widget,
212 gpointer data)
214 #if 0
215 GtkWidget *dialog;
216 gint result;
217 #endif
218 struct join_state *state = (struct join_state *)data;
220 if (!state->settings_changed) {
221 callback_delete_event(NULL, NULL, NULL);
222 return;
225 #if 0
226 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
227 GTK_DIALOG_DESTROY_WITH_PARENT,
228 GTK_MESSAGE_QUESTION,
229 GTK_BUTTONS_YES_NO,
230 "You must restart your computer before the new settings will take effect.");
231 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
232 result = gtk_dialog_run(GTK_DIALOG(dialog));
233 switch (result) {
234 case GTK_RESPONSE_YES:
235 g_print("would reboot here\n");
236 break;
237 case GTK_RESPONSE_NO:
238 default:
239 break;
241 if (dialog) {
242 gtk_widget_destroy(GTK_WIDGET(dialog));
244 #endif
245 if (state->window_main) {
246 gtk_widget_destroy(GTK_WIDGET(state->window_main));
247 state->window_main = NULL;
249 do_cleanup(state);
250 exit(0);
254 static void callback_do_reboot(GtkWidget *widget,
255 gpointer data,
256 gpointer data2)
258 GtkWidget *dialog;
259 struct join_state *state = (struct join_state *)data2;
261 debug("callback_do_reboot\n");
263 state->settings_changed = TRUE;
264 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
265 GTK_DIALOG_DESTROY_WITH_PARENT,
266 GTK_MESSAGE_INFO,
267 GTK_BUTTONS_OK,
268 "You must restart this computer for the changes to take effect.");
269 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
270 #if 0
271 g_signal_connect_swapped(dialog, "response",
272 G_CALLBACK(gtk_widget_destroy),
273 dialog);
275 debug("showing dialog\n");
276 gtk_widget_show(dialog);
277 #else
278 gtk_dialog_run(GTK_DIALOG(dialog));
279 gtk_widget_destroy(GTK_WIDGET(dialog));
280 #endif
282 gtk_label_set_text(GTK_LABEL(state->label_reboot),
283 "Changes will take effect after you restart this computer");
285 debug("destroying do_change window\n");
286 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
289 uint32_t status;
290 const char *buffer;
291 uint16_t type;
293 status = NetGetJoinInformation(NULL, &buffer, &type);
294 if (status != 0) {
295 g_print("failed to query status\n");
296 return;
299 debug("got new status: %s\n", buffer);
300 #if 0
301 SAFE_FREE(state->name_buffer_new);
302 state->name_buffer_new = strdup(buffer);
303 SAFE_FREE(buffer);
304 state->name_type_new = type;
305 #endif
306 NetApiBufferFree((void *)buffer);
308 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
309 state->name_buffer_new);
310 if (state->name_type_new == NetSetupDomainName) {
311 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
312 "Domain:");
313 } else {
314 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
315 "Workgroup:");
320 static void callback_return_username(GtkWidget *widget,
321 gpointer data)
323 const gchar *entry_text;
324 struct join_state *state = (struct join_state *)data;
325 debug("callback_return_username called\n");
326 if (!widget) {
327 return;
329 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
330 if (!entry_text) {
331 return;
333 debug("callback_return_username: %s\n", entry_text);
334 SAFE_FREE(state->account);
335 state->account = strdup(entry_text);
338 static void callback_return_username_and_enter(GtkWidget *widget,
339 gpointer data)
341 const gchar *entry_text;
342 struct join_state *state = (struct join_state *)data;
343 if (!widget) {
344 return;
346 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
347 if (!entry_text) {
348 return;
350 debug("callback_return_username_and_enter: %s\n", entry_text);
351 SAFE_FREE(state->account);
352 state->account = strdup(entry_text);
353 g_signal_emit_by_name(state->button_ok_creds, "clicked");
356 static void callback_return_password(GtkWidget *widget,
357 gpointer data)
359 const gchar *entry_text;
360 struct join_state *state = (struct join_state *)data;
361 debug("callback_return_password called\n");
362 if (!widget) {
363 return;
365 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
366 if (!entry_text) {
367 return;
369 #ifdef DEBUG_PASSWORD
370 debug("callback_return_password: %s\n", entry_text);
371 #else
372 debug("callback_return_password: (not printed)\n");
373 #endif
374 SAFE_FREE(state->password);
375 state->password = strdup(entry_text);
378 static void callback_return_password_and_enter(GtkWidget *widget,
379 gpointer data)
381 const gchar *entry_text;
382 struct join_state *state = (struct join_state *)data;
383 if (!widget) {
384 return;
386 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
387 if (!entry_text) {
388 return;
390 #ifdef DEBUG_PASSWORD
391 debug("callback_return_password_and_enter: %s\n", entry_text);
392 #else
393 debug("callback_return_password_and_enter: (not printed)\n");
394 #endif
395 SAFE_FREE(state->password);
396 state->password = strdup(entry_text);
397 g_signal_emit_by_name(state->button_ok_creds, "clicked");
400 static void callback_do_storeauth(GtkWidget *widget,
401 gpointer data)
403 struct join_state *state = (struct join_state *)data;
405 debug("callback_do_storeauth called\n");
407 SAFE_FREE(state->account);
408 SAFE_FREE(state->password);
410 callback_return_username(state->entry_account, (gpointer)state);
411 callback_return_password(state->entry_password, (gpointer)state);
413 if (state->window_creds_prompt) {
414 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
415 state->window_creds_prompt = NULL;
419 static void callback_continue(GtkWidget *widget,
420 gpointer data)
422 struct join_state *state = (struct join_state *)data;
424 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
425 g_signal_emit_by_name(state->button_ok, "clicked");
428 static void callback_do_storeauth_and_continue(GtkWidget *widget,
429 gpointer data)
431 callback_do_storeauth(widget, data);
432 callback_continue(NULL, data);
435 static void callback_do_storeauth_and_scan(GtkWidget *widget,
436 gpointer data)
438 struct join_state *state = (struct join_state *)data;
439 callback_do_storeauth(widget, data);
440 g_signal_emit_by_name(state->button_get_ous, "clicked");
443 static void callback_do_hostname_change(GtkWidget *widget,
444 gpointer data)
446 GtkWidget *dialog;
447 const char *str = NULL;
449 struct join_state *state = (struct join_state *)data;
451 switch (state->name_type_initial) {
452 case NetSetupDomainName:
453 str = "To be implemented: call NetRenameMachineInDomain\n";
454 break;
455 case NetSetupWorkgroupName:
456 str = "To be implemented: call SetComputerNameEx\n";
457 break;
458 default:
459 break;
462 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
463 GTK_DIALOG_DESTROY_WITH_PARENT,
464 GTK_MESSAGE_ERROR,
465 GTK_BUTTONS_CLOSE,
466 str);
468 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
469 g_signal_connect_swapped(dialog, "response",
470 G_CALLBACK(gtk_widget_destroy),
471 dialog);
472 gtk_widget_show(dialog);
475 static void callback_creds_prompt(GtkWidget *widget,
476 gpointer data,
477 const char *label_string,
478 gpointer cont_fn)
480 GtkWidget *window;
481 GtkWidget *box1;
482 GtkWidget *bbox;
483 GtkWidget *button;
484 GtkWidget *label;
486 struct join_state *state = (struct join_state *)data;
488 debug("callback_creds_prompt\n");
490 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
491 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
493 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
494 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
495 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
496 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
497 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
499 g_signal_connect(G_OBJECT(window), "delete_event",
500 G_CALLBACK(callback_do_close), window);
502 state->window_creds_prompt = window;
503 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
505 box1 = gtk_vbox_new(FALSE, 0);
507 gtk_container_add(GTK_CONTAINER(window), box1);
509 label = gtk_label_new(label_string);
510 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
511 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
513 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
515 gtk_widget_show(label);
517 /* USER NAME */
518 label = gtk_label_new("User name:");
519 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
520 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
521 gtk_widget_show(label);
523 state->entry_account = gtk_entry_new();
524 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
525 g_signal_connect(G_OBJECT(state->entry_account), "activate",
526 G_CALLBACK(callback_return_username_and_enter),
527 (gpointer)state);
528 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
529 0, GTK_ENTRY(state->entry_account)->text_length);
530 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
531 gtk_widget_show(state->entry_account);
533 /* PASSWORD */
534 label = gtk_label_new("Password:");
535 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
536 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
537 gtk_widget_show(label);
539 state->entry_password = gtk_entry_new();
540 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
541 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
542 g_signal_connect(G_OBJECT(state->entry_password), "activate",
543 G_CALLBACK(callback_return_password_and_enter),
544 (gpointer)state);
545 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
546 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
547 0, GTK_ENTRY(state->entry_password)->text_length);
548 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
549 gtk_widget_show(state->entry_password);
551 /* BUTTONS */
552 bbox = gtk_hbutton_box_new();
553 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
554 gtk_container_add(GTK_CONTAINER(box1), bbox);
555 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
556 gtk_box_set_spacing(GTK_BOX(bbox), 10);
558 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
559 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
560 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
561 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
562 G_CALLBACK(cont_fn),
563 (gpointer)state);
564 gtk_widget_show(state->button_ok_creds);
566 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
567 gtk_container_add(GTK_CONTAINER(bbox), button);
568 g_signal_connect(G_OBJECT(button), "clicked",
569 G_CALLBACK(callback_do_freeauth),
570 (gpointer)state);
571 gtk_widget_show_all(window);
574 static void callback_do_join(GtkWidget *widget,
575 gpointer data)
577 GtkWidget *dialog;
579 NET_API_STATUS status;
580 const char *err_str = NULL;
581 uint32_t join_flags = 0;
582 uint32_t unjoin_flags = 0;
583 gboolean domain_join = FALSE;
584 gboolean try_unjoin = FALSE;
585 gboolean join_creds_required = TRUE;
586 gboolean unjoin_creds_required = TRUE;
587 const char *new_workgroup_type = NULL;
588 const char *initial_workgroup_type = NULL;
589 const char *account_ou = NULL;
591 struct join_state *state = (struct join_state *)data;
593 if (state->hostname_changed) {
594 callback_do_hostname_change(NULL, state);
595 return;
598 switch (state->name_type_initial) {
599 case NetSetupWorkgroupName:
600 initial_workgroup_type = "workgroup";
601 break;
602 case NetSetupDomainName:
603 initial_workgroup_type = "domain";
604 break;
605 default:
606 break;
609 switch (state->name_type_new) {
610 case NetSetupWorkgroupName:
611 new_workgroup_type = "workgroup";
612 break;
613 case NetSetupDomainName:
614 new_workgroup_type = "domain";
615 break;
616 default:
617 break;
620 account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
621 if (account_ou && strlen(account_ou) == 0) {
622 account_ou = NULL;
625 if ((state->name_type_initial != NetSetupDomainName) &&
626 (state->name_type_new != NetSetupDomainName)) {
627 join_creds_required = FALSE;
628 unjoin_creds_required = FALSE;
631 if (state->name_type_new == NetSetupDomainName) {
632 domain_join = TRUE;
633 join_creds_required = TRUE;
634 join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
635 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
636 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED; /* for testing */
639 if ((state->name_type_initial == NetSetupDomainName) &&
640 (state->name_type_new == NetSetupWorkgroupName)) {
641 try_unjoin = TRUE;
642 unjoin_creds_required = TRUE;
643 join_creds_required = FALSE;
644 unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
645 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
648 if (try_unjoin) {
650 debug("callback_do_join: Unjoining\n");
652 if (unjoin_creds_required) {
653 if (!state->account || !state->password) {
654 debug("callback_do_join: no creds yet\n");
655 callback_creds_prompt(NULL, state,
656 "Enter the name and password of an account with permission to leave the domain.",
657 callback_do_storeauth_and_continue);
660 if (!state->account || !state->password) {
661 debug("callback_do_join: still no creds???\n");
662 return;
666 status = NetUnjoinDomain(NULL,
667 state->account,
668 state->password,
669 unjoin_flags);
670 if (status != 0) {
671 callback_do_freeauth(NULL, state);
672 err_str = libnetapi_get_error_string(state->ctx, status);
673 g_print("callback_do_join: failed to unjoin (%s)\n",
674 err_str);
675 #if 0
677 /* in fact we shouldn't annoy the user with an error message here */
679 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
680 GTK_DIALOG_DESTROY_WITH_PARENT,
681 GTK_MESSAGE_ERROR,
682 GTK_BUTTONS_CLOSE,
683 "The following error occured attempting to unjoin the %s: \"%s\": %s",
684 initial_workgroup_type,
685 state->name_buffer_initial,
686 err_str);
687 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
688 gtk_dialog_run(GTK_DIALOG(dialog));
689 gtk_widget_destroy(dialog);
690 #endif
695 /* before prompting for creds, make sure we can find a dc */
697 if (domain_join) {
699 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
701 status = DsGetDcName(NULL,
702 state->name_buffer_new,
703 NULL,
704 NULL,
706 &dc_info);
707 if (status != 0) {
708 err_str = libnetapi_get_error_string(state->ctx, status);
709 g_print("callback_do_join: failed find dc (%s)\n", err_str);
711 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
712 GTK_DIALOG_DESTROY_WITH_PARENT,
713 GTK_MESSAGE_ERROR,
714 GTK_BUTTONS_CLOSE,
715 "Failed to find a domain controller for domain: \"%s\": %s",
716 state->name_buffer_new,
717 err_str);
719 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
720 g_signal_connect_swapped(dialog, "response",
721 G_CALLBACK(gtk_widget_destroy),
722 dialog);
724 gtk_widget_show(dialog);
726 return;
730 if (join_creds_required) {
731 if (!state->account || !state->password) {
732 debug("callback_do_join: no creds yet\n");
733 callback_creds_prompt(NULL, state,
734 "Enter the name and password of an account with permission to leave the domain.",
735 callback_do_storeauth_and_continue);
738 if (!state->account || !state->password) {
739 debug("callback_do_join: still no creds???\n");
740 return;
744 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
745 new_workgroup_type,
746 state->name_buffer_new,
747 join_flags);
748 if (domain_join) {
749 debug("as %s ", state->account);
750 #ifdef DEBUG_PASSWORD
751 debug("with %s ", state->password);
752 #endif
754 debug("\n");
756 status = NetJoinDomain(NULL,
757 state->name_buffer_new,
758 account_ou,
759 state->account,
760 state->password,
761 join_flags);
762 if (status != 0) {
763 callback_do_freeauth(NULL, state);
764 err_str = libnetapi_get_error_string(state->ctx, status);
765 g_print("callback_do_join: failed to join (%s)\n", err_str);
767 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
768 GTK_DIALOG_DESTROY_WITH_PARENT,
769 GTK_MESSAGE_ERROR,
770 GTK_BUTTONS_CLOSE,
771 "The following error occured attempting to join the %s: \"%s\": %s",
772 new_workgroup_type,
773 state->name_buffer_new,
774 err_str);
776 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
777 g_signal_connect_swapped(dialog, "response",
778 G_CALLBACK(gtk_widget_destroy),
779 dialog);
781 gtk_widget_show(dialog);
783 return;
786 debug("callback_do_join: Successfully joined %s\n",
787 new_workgroup_type);
789 callback_do_freeauth(NULL, state);
790 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
791 GTK_DIALOG_DESTROY_WITH_PARENT,
792 GTK_MESSAGE_INFO,
793 GTK_BUTTONS_OK,
794 "Welcome to the %s %s.",
795 state->name_buffer_new,
796 new_workgroup_type);
798 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
799 gtk_dialog_run(GTK_DIALOG(dialog));
800 gtk_widget_destroy(dialog);
802 callback_do_reboot(NULL, state->window_parent, state);
805 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
806 gpointer data)
808 const gchar *entry_text = NULL;
809 char *str = NULL;
810 struct join_state *state = (struct join_state *)data;
812 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
813 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
814 if (!entry_text || entry_text[0] == 0) {
815 state->hostname_changed = FALSE;
816 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
817 return;
819 if (strcasecmp(state->my_hostname, entry_text) == 0) {
820 state->hostname_changed = FALSE;
821 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
822 return;
824 state->hostname_changed = TRUE;
825 if (state->name_type_initial == NetSetupDomainName) {
826 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
827 } else {
828 asprintf(&str, "%s.", entry_text);
830 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
831 free(str);
833 if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
834 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
838 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
839 gpointer data)
841 const gchar *entry_text = NULL;
842 struct join_state *state = (struct join_state *)data;
843 int string_unchanged = 0;
845 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
846 debug("callback_enter_computer_description_and_unlock: %s\n",
847 entry_text);
848 #if 0
849 if (!entry_text || entry_text[0] == 0) {
850 string_unchanged = 1;
851 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
852 FALSE);
853 return;
855 #endif
856 if (entry_text && strcasecmp(state->comment, entry_text) == 0) {
857 string_unchanged = 1;
858 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
859 FALSE);
860 return;
863 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
864 SAFE_FREE(state->comment_new);
865 state->comment_new = strdup(entry_text);
870 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
871 gpointer data)
873 const gchar *entry_text = NULL;
874 struct join_state *state = (struct join_state *)data;
876 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
877 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
878 if (!entry_text || entry_text[0] == 0) {
879 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
880 return;
882 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
883 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
884 return;
886 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
887 SAFE_FREE(state->name_buffer_new);
888 state->name_buffer_new = strdup(entry_text);
889 state->name_type_new = NetSetupWorkgroupName;
892 static void callback_enter_domain_and_unlock(GtkWidget *widget,
893 gpointer data)
895 const gchar *entry_text = NULL;
896 struct join_state *state = (struct join_state *)data;
898 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
899 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
900 if (!entry_text || entry_text[0] == 0) {
901 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
902 return;
904 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
905 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
906 return;
908 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
909 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
910 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
911 SAFE_FREE(state->name_buffer_new);
912 state->name_buffer_new = strdup(entry_text);
913 state->name_type_new = NetSetupDomainName;
916 static void callback_apply_continue(GtkWidget *widget,
917 gpointer data)
919 struct join_state *state = (struct join_state *)data;
921 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
922 g_signal_emit_by_name(state->button_apply, "clicked");
925 static void callback_do_join_workgroup(GtkWidget *widget,
926 gpointer data)
928 struct join_state *state = (struct join_state *)data;
929 debug("callback_do_join_workgroup choosen\n");
930 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
931 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
932 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
933 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
934 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
935 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
938 static void callback_do_join_domain(GtkWidget *widget,
939 gpointer data)
941 struct join_state *state = (struct join_state *)data;
942 debug("callback_do_join_domain choosen\n");
943 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
944 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
945 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
946 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
949 static void callback_do_getous(GtkWidget *widget,
950 gpointer data)
952 NET_API_STATUS status;
953 uint32_t num_ous = 0;
954 const char **ous = NULL;
955 int i;
956 const char *domain = NULL;
957 struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
958 const char *err_str = NULL;
959 GtkWidget *dialog;
961 struct join_state *state = (struct join_state *)data;
963 debug("callback_do_getous called\n");
965 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
967 status = DsGetDcName(NULL,
968 domain,
969 NULL,
970 NULL,
972 &dc_info);
973 if (status != 0) {
974 err_str = libnetapi_get_error_string(state->ctx, status);
975 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
977 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
978 GTK_DIALOG_DESTROY_WITH_PARENT,
979 GTK_MESSAGE_ERROR,
980 GTK_BUTTONS_CLOSE,
981 "Failed to find a domain controller for domain: \"%s\": %s",
982 domain,
983 err_str);
985 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
986 g_signal_connect_swapped(dialog, "response",
987 G_CALLBACK(gtk_widget_destroy),
988 dialog);
990 gtk_widget_show(dialog);
992 return;
995 if (!state->account || !state->password) {
996 debug("callback_do_getous: no creds yet\n");
997 callback_creds_prompt(NULL, state,
998 "Enter the name and password of an account with permission to join the domain.",
999 callback_do_storeauth_and_scan);
1002 if (!state->account || !state->password) {
1003 debug("callback_do_getous: still no creds ???\n");
1004 return;
1007 status = NetGetJoinableOUs(NULL, domain,
1008 state->account,
1009 state->password,
1010 &num_ous, &ous);
1011 if (status != NET_API_STATUS_SUCCESS) {
1012 callback_do_freeauth(NULL, state);
1013 debug("failed to call NetGetJoinableOUs: %s\n",
1014 libnetapi_get_error_string(state->ctx, status));
1015 dialog = gtk_message_dialog_new(NULL,
1016 GTK_DIALOG_DESTROY_WITH_PARENT,
1017 GTK_MESSAGE_INFO,
1018 GTK_BUTTONS_OK,
1019 "Failed to query joinable OUs: %s",
1020 libnetapi_get_error_string(state->ctx, status));
1021 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1022 gtk_dialog_run(GTK_DIALOG(dialog));
1023 gtk_widget_destroy(dialog);
1024 return;
1027 for (i=0; i<state->stored_num_ous; i++) {
1028 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1030 for (i=0; i<num_ous && ous[i] != NULL; i++) {
1031 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1032 ous[i]);
1034 NetApiBufferFree(ous);
1035 state->stored_num_ous = num_ous;
1036 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1039 static void callback_do_change(GtkWidget *widget,
1040 gpointer data)
1042 GtkWidget *window;
1043 GtkWidget *box1;
1044 GtkWidget *bbox;
1045 GtkWidget *button_workgroup;
1046 GtkWidget *button_domain;
1047 GtkWidget *button;
1048 GtkWidget *label;
1049 GtkWidget *frame_horz;
1050 GtkWidget *vbox;
1051 GtkWidget *entry;
1052 GSList *group;
1054 struct join_state *state = (struct join_state *)data;
1056 debug("callback_do_change called\n");
1058 #if 0
1059 /* FIXME: add proper warnings for Samba as a DC */
1060 if (state->server_role == 3) {
1061 GtkWidget *dialog;
1062 callback_do_freeauth(NULL, state);
1063 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1064 GTK_DIALOG_DESTROY_WITH_PARENT,
1065 GTK_MESSAGE_ERROR,
1066 GTK_BUTTONS_OK,
1067 "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.");
1068 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1069 g_signal_connect_swapped(dialog, "response",
1070 G_CALLBACK(gtk_widget_destroy),
1071 dialog);
1073 gtk_widget_show(dialog);
1074 return;
1076 #endif
1078 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1079 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1080 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1081 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1083 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1084 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1085 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1086 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1088 g_signal_connect(G_OBJECT(window), "delete_event",
1089 G_CALLBACK(callback_do_close), window);
1091 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1093 box1 = gtk_vbox_new(FALSE, 0);
1094 gtk_container_add(GTK_CONTAINER(window), box1);
1096 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1097 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1098 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1099 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1100 gtk_widget_show(label);
1102 /* COMPUTER NAME */
1103 label = gtk_label_new("Computer name:");
1104 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1105 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1106 gtk_widget_show(label);
1108 state->label_full_computer_name = gtk_label_new(NULL);
1110 entry = gtk_entry_new();
1111 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1112 g_signal_connect(G_OBJECT(entry), "changed",
1113 G_CALLBACK(callback_enter_hostname_and_unlock),
1114 (gpointer)state);
1115 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1116 gtk_editable_select_region(GTK_EDITABLE(entry),
1117 0, GTK_ENTRY(entry)->text_length);
1119 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1120 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1121 gtk_widget_show(entry);
1124 /* FULL COMPUTER NAME */
1125 label = gtk_label_new("Full computer name:");
1126 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1127 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1128 gtk_widget_show(label);
1131 const gchar *entry_text;
1132 char *str = NULL;
1133 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1134 if (state->name_type_initial == NetSetupDomainName) {
1135 asprintf(&str, "%s.%s", entry_text,
1136 state->my_dnsdomain);
1137 } else {
1138 asprintf(&str, "%s.", entry_text);
1140 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1141 str);
1142 free(str);
1143 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1144 gtk_box_pack_start(GTK_BOX(box1),
1145 state->label_full_computer_name, TRUE, TRUE, 0);
1146 gtk_widget_show(state->label_full_computer_name);
1149 /* BOX */
1150 frame_horz = gtk_frame_new ("Member Of");
1151 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1153 vbox = gtk_vbox_new(FALSE, 0);
1154 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1155 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1157 /* TWO ENTRIES */
1158 state->entry_workgroup = gtk_entry_new();
1159 state->entry_domain = gtk_entry_new();
1161 /* DOMAIN */
1162 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1163 if (state->name_type_initial == NetSetupDomainName) {
1164 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1166 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1167 g_signal_connect(G_OBJECT(button_domain), "clicked",
1168 G_CALLBACK(callback_do_join_domain),
1169 (gpointer)state);
1172 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1173 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1174 G_CALLBACK(callback_enter_domain_and_unlock),
1175 (gpointer)state);
1176 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1177 G_CALLBACK(callback_continue),
1178 (gpointer)state);
1179 if (state->name_type_initial == NetSetupDomainName) {
1180 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1181 state->name_buffer_initial);
1182 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1183 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1185 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1186 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1187 gtk_widget_show(state->entry_domain);
1189 gtk_widget_show(button_domain);
1191 /* WORKGROUP */
1192 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1193 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1194 if (state->name_type_initial == NetSetupWorkgroupName) {
1195 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1197 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1198 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1199 G_CALLBACK(callback_do_join_workgroup),
1200 (gpointer)state);
1202 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1203 MAX_NETBIOS_NAME_LEN);
1204 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1205 G_CALLBACK(callback_enter_workgroup_and_unlock),
1206 (gpointer)state);
1207 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1208 G_CALLBACK(callback_continue),
1209 (gpointer)state);
1211 if (state->name_type_initial == NetSetupWorkgroupName) {
1212 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1213 state->name_buffer_initial);
1214 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1215 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1217 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1218 gtk_widget_show(state->entry_workgroup);
1220 gtk_widget_show(button_workgroup);
1222 /* Advanced Options */
1223 frame_horz = gtk_frame_new("Advanced Options");
1224 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1226 vbox = gtk_vbox_new(FALSE, 0);
1227 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1228 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1230 /* OUs */
1231 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1232 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1233 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1234 G_CALLBACK(callback_do_getous),
1235 (gpointer)state);
1237 state->entry_ou_list = gtk_combo_box_entry_new_text();
1238 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1239 if (state->name_type_initial == NetSetupWorkgroupName) {
1240 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1241 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1243 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1244 gtk_widget_show(state->entry_ou_list);
1247 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1248 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1249 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1253 /* BUTTONS */
1254 bbox = gtk_hbutton_box_new();
1255 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1256 gtk_container_add(GTK_CONTAINER(box1), bbox);
1257 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1258 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1260 state->window_do_change = window;
1261 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1262 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1263 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1264 G_CALLBACK(callback_do_join),
1265 (gpointer)state);
1267 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1268 gtk_container_add(GTK_CONTAINER(bbox), button);
1269 g_signal_connect(G_OBJECT(button), "clicked",
1270 G_CALLBACK(callback_do_freeauth_and_close),
1271 (gpointer)state);
1273 gtk_widget_show_all(window);
1276 static void callback_do_about(GtkWidget *widget,
1277 gpointer data)
1279 GdkPixbuf *logo;
1280 GError *error = NULL;
1281 GtkWidget *about;
1283 debug("callback_do_about called\n");
1285 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1286 &error);
1287 if (logo == NULL) {
1288 g_print("failed to load logo from %s: %s\n",
1289 SAMBA_IMAGE_PATH, error->message);
1292 about = gtk_about_dialog_new();
1293 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1294 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1295 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1296 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1297 "Copyright Günther Deschner 2007-2008");
1298 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1299 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1300 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1301 if (logo) {
1302 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1304 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1305 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1306 g_signal_connect_swapped(about, "response",
1307 G_CALLBACK(gtk_widget_destroy),
1308 about);
1310 gtk_widget_show(about);
1313 static int draw_main_window(struct join_state *state)
1315 GtkWidget *window;
1316 GtkWidget *button;
1317 GtkWidget *label;
1318 GtkWidget *main_vbox;
1319 GtkWidget *vbox;
1320 GtkWidget *hbox;
1321 GtkWidget *bbox;
1322 GtkWidget *image;
1323 GtkWidget *table;
1324 GtkWidget *entry;
1325 GdkPixbuf *icon;
1326 GError *error = NULL;
1328 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1329 &error);
1330 if (icon == NULL) {
1331 g_print("failed to load icon from %s : %s\n",
1332 SAMBA_ICON_PATH, error->message);
1335 #if 1
1336 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1337 #else
1338 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1339 #endif
1340 if (image == NULL) {
1341 g_print("failed to load logo from %s : %s\n",
1342 SAMBA_IMAGE_PATH_SMALL, error->message);
1345 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1346 state->window_main = window;
1348 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1349 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1350 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1351 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1353 g_signal_connect(G_OBJECT(window), "delete_event",
1354 G_CALLBACK(callback_delete_event), NULL);
1356 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1358 main_vbox = gtk_vbox_new(FALSE, 10);
1359 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1361 #if 0
1362 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1363 gtk_widget_show(image);
1364 #endif
1365 /* Hbox */
1366 hbox = gtk_hbox_new(FALSE, 10);
1367 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1370 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1371 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1372 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1373 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1374 gtk_widget_show(image);
1376 /* Label */
1377 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1378 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1379 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1380 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1381 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1382 gtk_widget_show(label);
1385 gtk_widget_show(hbox);
1387 vbox = gtk_vbox_new(FALSE, 0);
1388 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1389 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1391 /* Table */
1392 table = gtk_table_new(6, 3, TRUE);
1393 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1394 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1395 gtk_container_add(GTK_CONTAINER(vbox), table);
1398 /* Label */
1399 label = gtk_label_new("Computer description:");
1400 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1401 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1402 gtk_widget_show(label);
1404 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1406 /* Entry */
1407 entry = gtk_entry_new();
1408 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1409 g_signal_connect(G_OBJECT(entry), "changed",
1410 G_CALLBACK(callback_enter_computer_description_and_unlock),
1411 state);
1412 g_signal_connect(G_OBJECT(entry), "activate",
1413 G_CALLBACK(callback_apply_continue),
1414 (gpointer)state);
1416 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1417 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1418 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1419 gtk_widget_show(entry);
1422 /* Label */
1423 label = gtk_label_new("For example: \"Samba \%v\".");
1424 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1425 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1426 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1427 gtk_widget_show(label);
1429 /* Label */
1430 label = gtk_label_new("Full computer name:");
1431 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1432 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1433 gtk_widget_show(label);
1436 /* Label */
1437 char *str = NULL;
1438 if (state->name_type_initial == NetSetupDomainName) {
1439 asprintf(&str, "%s.%s", state->my_hostname,
1440 state->my_dnsdomain);
1441 } else {
1442 asprintf(&str, "%s.", state->my_hostname);
1445 label = gtk_label_new(str);
1446 SAFE_FREE(str);
1447 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1448 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1449 gtk_widget_show(label);
1452 /* Label */
1453 if (state->name_type_initial == NetSetupDomainName) {
1454 label = gtk_label_new("Domain:");
1455 } else {
1456 label = gtk_label_new("Workgroup:");
1458 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1459 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1460 gtk_widget_show(label);
1461 state->label_current_name_type = label;
1463 /* Label */
1464 label = gtk_label_new(state->name_buffer_initial);
1465 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1466 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1467 gtk_widget_show(label);
1468 state->label_current_name_buffer = label;
1471 hbox = gtk_hbox_new(FALSE, 0);
1472 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1473 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1474 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1479 /* bbox */
1480 bbox = gtk_hbutton_box_new();
1481 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1482 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1483 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1484 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1486 button = gtk_button_new_with_mnemonic("Ch_ange");
1487 g_signal_connect(G_OBJECT(button), "clicked",
1488 G_CALLBACK(callback_do_change),
1489 (gpointer)state);
1490 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1491 gtk_widget_show(button);
1493 /* Label (hidden) */
1494 state->label_reboot = gtk_label_new(NULL);
1495 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1496 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1497 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1498 gtk_widget_show(state->label_reboot);
1500 #if 0
1501 gtk_box_pack_start(GTK_BOX(vbox),
1502 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1503 TRUE, TRUE, 5);
1504 #endif
1507 GtkWidget *frame;
1508 GtkWidget *bbox2;
1509 GtkWidget *button2;
1511 frame = gtk_frame_new(NULL);
1512 bbox2 = gtk_hbutton_box_new();
1514 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1515 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1517 /* Set the appearance of the Button Box */
1518 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1519 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1520 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1522 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1523 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1524 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1526 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1527 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1528 g_signal_connect(G_OBJECT(button2), "clicked",
1529 G_CALLBACK(callback_delete_event),
1530 window);
1532 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1533 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1534 G_CALLBACK(callback_apply_description_change),
1535 state);
1536 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1538 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1539 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1540 g_signal_connect(G_OBJECT(button2), "clicked",
1541 G_CALLBACK(callback_do_about),
1542 window);
1543 #if 0
1544 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1545 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1546 g_signal_connect(G_OBJECT(button2), "clicked",
1547 G_CALLBACK(callback_do_about),
1548 window);
1549 #endif
1550 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1553 gtk_widget_show_all(window);
1555 return 0;
1558 static int init_join_state(struct join_state **state)
1560 struct join_state *s;
1562 s = (struct join_state *)malloc(sizeof(struct join_state));
1563 if (!s) {
1564 return -1;
1567 memset(s, '\0', sizeof(struct join_state));
1569 *state = s;
1571 return 0;
1574 static int initialize_join_state(struct join_state *state,
1575 const char *debug_level)
1577 struct libnetapi_ctx *ctx = NULL;
1578 NET_API_STATUS status = 0;
1580 status = libnetapi_init(&ctx);
1581 if (status) {
1582 return status;
1585 if (debug_level) {
1586 libnetapi_set_debuglevel(ctx, debug_level);
1590 char my_hostname[HOST_NAME_MAX];
1591 const char *p = NULL;
1592 struct hostent *hp = NULL;
1594 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1595 return -1;
1598 p = strchr(my_hostname, '.');
1599 if (p) {
1600 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1602 state->my_hostname = strdup(my_hostname);
1603 if (!state->my_hostname) {
1604 return -1;
1606 debug("state->my_hostname: %s\n", state->my_hostname);
1608 hp = gethostbyname(my_hostname);
1609 if (!hp || !hp->h_name || !*hp->h_name) {
1610 return -1;
1613 state->my_fqdn = strdup(hp->h_name);
1614 if (!state->my_fqdn) {
1615 return -1;
1617 debug("state->my_fqdn: %s\n", state->my_fqdn);
1619 p = strchr(state->my_fqdn, '.');
1620 if (p) {
1621 p++;
1622 state->my_dnsdomain = strdup(p);
1623 } else {
1624 state->my_dnsdomain = strdup("");
1626 if (!state->my_dnsdomain) {
1627 return -1;
1629 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1633 const char *buffer = NULL;
1634 uint16_t type = 0;
1635 status = NetGetJoinInformation(NULL, &buffer, &type);
1636 if (status != 0) {
1637 printf("NetGetJoinInformation failed with: %s\n",
1638 libnetapi_get_error_string(state->ctx, status));
1639 return status;
1641 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1642 state->name_buffer_initial = strdup(buffer);
1643 if (!state->name_buffer_initial) {
1644 return -1;
1646 state->name_type_initial = type;
1647 NetApiBufferFree((void *)buffer);
1651 struct SERVER_INFO_1005 *info1005 = NULL;
1652 uint8_t *buffer = NULL;
1654 status = NetServerGetInfo(NULL, 1005, &buffer);
1655 if (status != 0) {
1656 printf("NetServerGetInfo failed with: %s\n",
1657 libnetapi_get_error_string(state->ctx, status));
1658 return status;
1661 info1005 = (struct SERVER_INFO_1005 *)buffer;
1663 state->comment = strdup(info1005->sv1005_comment);
1664 if (!state->comment) {
1665 return -1;
1667 NetApiBufferFree(buffer);
1669 #if 0
1671 struct srvsvc_NetSrvInfo100 *info100 = NULL;
1672 uint8_t *buffer = NULL;
1674 status = NetServerGetInfo(NULL, 100, &buffer);
1675 if (status) {
1676 return status;
1679 info100 = (struct srvsvc_NetSrvInfo100 *)buffer;
1681 state->comment = strdup(info100->comment);
1682 if (!state->comment) {
1683 return -1;
1686 #endif
1688 state->ctx = ctx;
1690 return 0;
1693 int main(int argc, char **argv)
1695 GOptionContext *context = NULL;
1696 static const char *debug_level = NULL;
1697 struct join_state *state = NULL;
1698 GError *error = NULL;
1699 int ret = 0;
1701 static GOptionEntry entries[] = {
1702 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1703 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1704 { NULL }
1707 context = g_option_context_new("- Samba domain join utility");
1708 g_option_context_add_main_entries(context, entries, NULL);
1709 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1710 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1711 g_option_context_parse(context, &argc, &argv, &error);
1713 gtk_init(&argc, &argv);
1714 g_set_application_name("Samba");
1716 ret = init_join_state(&state);
1717 if (ret) {
1718 return ret;
1721 ret = initialize_join_state(state, debug_level);
1722 if (ret) {
1723 return ret;
1726 draw_main_window(state);
1728 gtk_main();
1730 do_cleanup(state);
1732 return 0;