netdomjoin-gui: Omit warning when unjoining a domain fails.
[Samba.git] / source / lib / netapi / examples / netdomjoin-gui / netdomjoin-gui.c
blob5ce4ca2c87b62ff2c3c83d38ee0c424cda6f9eb7
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 gtk_widget_destroy(data);
119 static void callback_do_freeauth(GtkWidget *widget,
120 gpointer data)
122 struct join_state *state = (struct join_state *)data;
124 debug("callback_do_freeauth called\n");
126 SAFE_FREE(state->account);
127 SAFE_FREE(state->password);
129 if (state->window_creds_prompt) {
130 gtk_widget_destroy(state->window_creds_prompt);
134 static void callback_do_freeauth_and_close(GtkWidget *widget,
135 gpointer data)
137 struct join_state *state = (struct join_state *)data;
139 debug("callback_do_freeauth_and_close called\n");
141 SAFE_FREE(state->account);
142 SAFE_FREE(state->password);
144 gtk_widget_destroy(state->window_creds_prompt);
145 gtk_widget_destroy(state->window_do_change);
148 static void free_join_state(struct join_state *s)
150 SAFE_FREE(s->name_buffer_initial);
151 SAFE_FREE(s->name_buffer_new);
152 SAFE_FREE(s->password);
153 SAFE_FREE(s->account);
154 SAFE_FREE(s->comment);
155 SAFE_FREE(s->comment_new);
156 SAFE_FREE(s->my_fqdn);
157 SAFE_FREE(s->my_dnsdomain);
158 SAFE_FREE(s->my_hostname);
161 static void do_cleanup(struct join_state *state)
163 libnetapi_free(state->ctx);
164 free_join_state(state);
167 static void callback_apply_description_change(GtkWidget *widget,
168 gpointer data)
170 struct join_state *state = (struct join_state *)data;
171 NET_API_STATUS status = 0;
172 uint32_t parm_err = 0;
173 struct SERVER_INFO_1005 info1005;
174 GtkWidget *dialog;
176 info1005.sv1005_comment = state->comment_new;
178 status = NetServerSetInfo(NULL, 1005, (uint8_t *)&info1005, &parm_err);
179 if (status) {
180 debug("NetServerSetInfo failed with: %s\n",
181 libnetapi_errstr(status));
182 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
183 GTK_DIALOG_DESTROY_WITH_PARENT,
184 GTK_MESSAGE_ERROR,
185 GTK_BUTTONS_OK,
186 "Failed to change computer description: %s.",
187 libnetapi_get_error_string(state->ctx, status));
188 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
190 g_signal_connect_swapped(dialog, "response",
191 G_CALLBACK(gtk_widget_destroy),
192 dialog);
194 gtk_widget_show(dialog);
195 return;
198 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
201 static void callback_do_exit(GtkWidget *widget,
202 gpointer data)
204 GtkWidget *dialog;
205 gint result;
206 struct join_state *state = (struct join_state *)data;
208 if (!state->settings_changed) {
209 callback_delete_event(NULL, NULL, NULL);
210 return;
213 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
214 GTK_DIALOG_DESTROY_WITH_PARENT,
215 GTK_MESSAGE_QUESTION,
216 GTK_BUTTONS_YES_NO,
217 "You must restart your computer before the new settings will take effect.");
218 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
219 result = gtk_dialog_run(GTK_DIALOG(dialog));
220 switch (result) {
221 case GTK_RESPONSE_YES:
222 g_print("would reboot here\n");
223 break;
224 case GTK_RESPONSE_NO:
225 default:
226 break;
228 gtk_widget_destroy(dialog);
229 gtk_widget_destroy(state->window_main);
230 do_cleanup(state);
231 exit(0);
235 static void callback_do_reboot(GtkWidget *widget,
236 gpointer data,
237 gpointer data2)
239 GtkWidget *dialog;
240 struct join_state *state = (struct join_state *)data2;
242 debug("callback_do_reboot\n");
244 state->settings_changed = TRUE;
245 dialog = gtk_message_dialog_new(GTK_WINDOW(data),
246 GTK_DIALOG_DESTROY_WITH_PARENT,
247 GTK_MESSAGE_INFO,
248 GTK_BUTTONS_OK,
249 "You must restart this computer for the changes to take effect.");
250 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
251 #if 0
252 g_signal_connect_swapped(dialog, "response",
253 G_CALLBACK(gtk_widget_destroy),
254 dialog);
256 debug("showing dialog\n");
257 gtk_widget_show(dialog);
258 #else
259 gtk_dialog_run(GTK_DIALOG(dialog));
260 gtk_widget_destroy(dialog);
261 #endif
263 gtk_label_set_text(GTK_LABEL(state->label_reboot),
264 "Changes will take effect after you restart this computer");
266 debug("destroying do_change window\n");
267 gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
270 uint32_t status;
271 const char *buffer;
272 uint16_t type;
274 status = NetGetJoinInformation(NULL, &buffer, &type);
275 if (status != 0) {
276 g_print("failed to query status\n");
277 return;
280 debug("got new status: %s\n", buffer);
281 #if 0
282 SAFE_FREE(state->name_buffer_new);
283 state->name_buffer_new = strdup(buffer);
284 SAFE_FREE(buffer);
285 state->name_type_new = type;
286 #endif
287 NetApiBufferFree((void *)buffer);
289 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
290 state->name_buffer_new);
291 if (state->name_type_new == NetSetupDomainName) {
292 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
293 "Domain:");
294 } else {
295 gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
296 "Workgroup:");
301 static void callback_return_username(GtkWidget *widget,
302 gpointer data)
304 const gchar *entry_text;
305 struct join_state *state = (struct join_state *)data;
306 debug("callback_return_username called\n");
307 if (!widget) {
308 return;
310 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
311 if (!entry_text) {
312 return;
314 debug("callback_return_username: %s\n", entry_text);
315 SAFE_FREE(state->account);
316 state->account = strdup(entry_text);
319 static void callback_return_username_and_enter(GtkWidget *widget,
320 gpointer data)
322 const gchar *entry_text;
323 struct join_state *state = (struct join_state *)data;
324 if (!widget) {
325 return;
327 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
328 if (!entry_text) {
329 return;
331 debug("callback_return_username_and_enter: %s\n", entry_text);
332 SAFE_FREE(state->account);
333 state->account = strdup(entry_text);
334 g_signal_emit_by_name(state->button_ok_creds, "clicked");
337 static void callback_return_password(GtkWidget *widget,
338 gpointer data)
340 const gchar *entry_text;
341 struct join_state *state = (struct join_state *)data;
342 debug("callback_return_password called\n");
343 if (!widget) {
344 return;
346 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
347 if (!entry_text) {
348 return;
350 #ifdef DEBUG_PASSWORD
351 debug("callback_return_password: %s\n", entry_text);
352 #else
353 debug("callback_return_password: (not printed)\n");
354 #endif
355 SAFE_FREE(state->password);
356 state->password = strdup(entry_text);
359 static void callback_return_password_and_enter(GtkWidget *widget,
360 gpointer data)
362 const gchar *entry_text;
363 struct join_state *state = (struct join_state *)data;
364 if (!widget) {
365 return;
367 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
368 if (!entry_text) {
369 return;
371 #ifdef DEBUG_PASSWORD
372 debug("callback_return_password_and_enter: %s\n", entry_text);
373 #else
374 debug("callback_return_password_and_enter: (not printed)\n");
375 #endif
376 SAFE_FREE(state->password);
377 state->password = strdup(entry_text);
378 g_signal_emit_by_name(state->button_ok_creds, "clicked");
381 static void callback_do_storeauth(GtkWidget *widget,
382 gpointer data)
384 struct join_state *state = (struct join_state *)data;
386 debug("callback_do_storeauth called\n");
388 SAFE_FREE(state->account);
389 SAFE_FREE(state->password);
391 callback_return_username(state->entry_account, state);
392 callback_return_password(state->entry_password, state);
394 gtk_widget_destroy(state->window_creds_prompt);
397 static void callback_continue(GtkWidget *widget,
398 gpointer data)
400 struct join_state *state = (struct join_state *)data;
402 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
403 g_signal_emit_by_name(state->button_ok, "clicked");
406 static void callback_do_storeauth_and_continue(GtkWidget *widget,
407 gpointer data)
409 callback_do_storeauth(widget, data);
410 callback_continue(NULL, data);
413 static void callback_do_storeauth_and_scan(GtkWidget *widget,
414 gpointer data)
416 struct join_state *state = (struct join_state *)data;
417 callback_do_storeauth(widget, data);
418 g_signal_emit_by_name(state->button_get_ous, "clicked");
421 static void callback_do_hostname_change(GtkWidget *widget,
422 gpointer data)
424 GtkWidget *dialog;
425 const char *str = NULL;
427 struct join_state *state = (struct join_state *)data;
429 switch (state->name_type_initial) {
430 case NetSetupDomainName:
431 str = "To be implemented: call NetRenameMachineInDomain\n";
432 break;
433 case NetSetupWorkgroupName:
434 str = "To be implemented: call SetComputerNameEx\n";
435 break;
436 default:
437 break;
440 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
441 GTK_DIALOG_DESTROY_WITH_PARENT,
442 GTK_MESSAGE_ERROR,
443 GTK_BUTTONS_CLOSE,
444 str);
446 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
447 g_signal_connect_swapped(dialog, "response",
448 G_CALLBACK(gtk_widget_destroy),
449 dialog);
450 gtk_widget_show(dialog);
453 static void callback_creds_prompt(GtkWidget *widget,
454 gpointer data,
455 const char *label_string,
456 gpointer cont_fn)
458 GtkWidget *window;
459 GtkWidget *box1;
460 GtkWidget *bbox;
461 GtkWidget *button;
462 GtkWidget *label;
464 struct join_state *state = (struct join_state *)data;
466 debug("callback_creds_prompt\n");
468 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
469 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
471 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
472 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
473 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
474 gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
475 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
477 g_signal_connect(G_OBJECT(window), "delete_event",
478 G_CALLBACK(callback_do_close), window);
480 state->window_creds_prompt = window;
481 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
483 box1 = gtk_vbox_new(FALSE, 0);
485 gtk_container_add(GTK_CONTAINER(window), box1);
487 label = gtk_label_new(label_string);
488 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
489 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
491 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
493 gtk_widget_show(label);
495 /* USER NAME */
496 label = gtk_label_new("User name:");
497 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
498 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
499 gtk_widget_show(label);
501 state->entry_account = gtk_entry_new();
502 gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
503 g_signal_connect(G_OBJECT(state->entry_account), "activate",
504 G_CALLBACK(callback_return_username_and_enter),
505 (gpointer)state);
506 gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
507 0, GTK_ENTRY(state->entry_account)->text_length);
508 gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
509 gtk_widget_show(state->entry_account);
511 /* PASSWORD */
512 label = gtk_label_new("Password:");
513 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
514 gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
515 gtk_widget_show(label);
517 state->entry_password = gtk_entry_new();
518 gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
519 gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
520 g_signal_connect(G_OBJECT(state->entry_password), "activate",
521 G_CALLBACK(callback_return_password_and_enter),
522 (gpointer)state);
523 gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
524 gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
525 0, GTK_ENTRY(state->entry_password)->text_length);
526 gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
527 gtk_widget_show(state->entry_password);
529 /* BUTTONS */
530 bbox = gtk_hbutton_box_new();
531 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
532 gtk_container_add(GTK_CONTAINER(box1), bbox);
533 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
534 gtk_box_set_spacing(GTK_BOX(bbox), 10);
536 state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
537 gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
538 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
539 g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
540 G_CALLBACK(cont_fn),
541 (gpointer)state);
542 gtk_widget_show(state->button_ok_creds);
544 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
545 gtk_container_add(GTK_CONTAINER(bbox), button);
546 g_signal_connect(G_OBJECT(button), "clicked",
547 G_CALLBACK(callback_do_freeauth),
548 (gpointer)state);
549 gtk_widget_show_all(window);
552 static void callback_do_join(GtkWidget *widget,
553 gpointer data)
555 GtkWidget *dialog;
557 NET_API_STATUS status;
558 const char *err_str = NULL;
559 uint32_t join_flags = 0;
560 uint32_t unjoin_flags = 0;
561 gboolean domain_join = FALSE;
562 gboolean try_unjoin = FALSE;
563 gboolean join_creds_required = TRUE;
564 gboolean unjoin_creds_required = TRUE;
565 const char *new_workgroup_type = NULL;
566 const char *initial_workgroup_type = NULL;
567 const char *account_ou = NULL;
569 struct join_state *state = (struct join_state *)data;
571 if (state->hostname_changed) {
572 callback_do_hostname_change(NULL, state);
573 return;
576 switch (state->name_type_initial) {
577 case NetSetupWorkgroupName:
578 initial_workgroup_type = "workgroup";
579 break;
580 case NetSetupDomainName:
581 initial_workgroup_type = "domain";
582 break;
583 default:
584 break;
587 switch (state->name_type_new) {
588 case NetSetupWorkgroupName:
589 new_workgroup_type = "workgroup";
590 break;
591 case NetSetupDomainName:
592 new_workgroup_type = "domain";
593 break;
594 default:
595 break;
598 account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
599 if (account_ou && strlen(account_ou) == 0) {
600 account_ou = NULL;
603 if ((state->name_type_initial != NetSetupDomainName) &&
604 (state->name_type_new != NetSetupDomainName)) {
605 join_creds_required = FALSE;
606 unjoin_creds_required = FALSE;
609 if (state->name_type_new == NetSetupDomainName) {
610 domain_join = TRUE;
611 join_creds_required = TRUE;
612 join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
613 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
614 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED; /* for testing */
617 if ((state->name_type_initial == NetSetupDomainName) &&
618 (state->name_type_new == NetSetupWorkgroupName)) {
619 try_unjoin = TRUE;
620 unjoin_creds_required = TRUE;
621 join_creds_required = FALSE;
622 unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
623 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
626 if (try_unjoin) {
628 debug("callback_do_join: Unjoining\n");
630 if (unjoin_creds_required) {
631 if (!state->account || !state->password) {
632 debug("callback_do_join: no creds yet\n");
633 callback_creds_prompt(NULL, state,
634 "Enter the name and password of an account with permission to leave the domain.",
635 callback_do_storeauth_and_continue);
638 if (!state->account || !state->password) {
639 debug("callback_do_join: still no creds???\n");
640 return;
644 status = NetUnjoinDomain(NULL,
645 state->account,
646 state->password,
647 unjoin_flags);
648 if (status != 0) {
649 callback_do_freeauth(NULL, state);
650 err_str = libnetapi_get_error_string(state->ctx, status);
651 g_print("callback_do_join: failed to unjoin (%s)\n",
652 err_str);
653 #if 0
655 /* in fact we shouldn't annoy the user with an error message here */
657 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
658 GTK_DIALOG_DESTROY_WITH_PARENT,
659 GTK_MESSAGE_ERROR,
660 GTK_BUTTONS_CLOSE,
661 "The following error occured attempting to unjoin the %s: \"%s\": %s",
662 initial_workgroup_type,
663 state->name_buffer_initial,
664 err_str);
665 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
666 gtk_dialog_run(GTK_DIALOG(dialog));
667 gtk_widget_destroy(dialog);
668 #endif
673 if (join_creds_required) {
674 if (!state->account || !state->password) {
675 debug("callback_do_join: no creds yet\n");
676 callback_creds_prompt(NULL, state,
677 "Enter the name and password of an account with permission to leave the domain.",
678 callback_do_storeauth_and_continue);
681 if (!state->account || !state->password) {
682 debug("callback_do_join: still no creds???\n");
683 return;
687 debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
688 new_workgroup_type,
689 state->name_buffer_new,
690 join_flags);
691 if (domain_join) {
692 debug("as %s ", state->account);
693 #ifdef DEBUG_PASSWORD
694 debug("with %s ", state->password);
695 #endif
697 debug("\n");
699 status = NetJoinDomain(NULL,
700 state->name_buffer_new,
701 account_ou,
702 state->account,
703 state->password,
704 join_flags);
705 if (status != 0) {
706 callback_do_freeauth(NULL, state);
707 err_str = libnetapi_get_error_string(state->ctx, status);
708 g_print("callback_do_join: failed to join (%s)\n", err_str);
710 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
711 GTK_DIALOG_DESTROY_WITH_PARENT,
712 GTK_MESSAGE_ERROR,
713 GTK_BUTTONS_CLOSE,
714 "The following error occured attempting to join the %s: \"%s\": %s",
715 new_workgroup_type,
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;
729 debug("callback_do_join: Successfully joined %s\n",
730 new_workgroup_type);
732 callback_do_freeauth(NULL, state);
733 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
734 GTK_DIALOG_DESTROY_WITH_PARENT,
735 GTK_MESSAGE_INFO,
736 GTK_BUTTONS_OK,
737 "Welcome to the %s %s.",
738 state->name_buffer_new,
739 new_workgroup_type);
741 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
742 gtk_dialog_run(GTK_DIALOG(dialog));
743 gtk_widget_destroy(dialog);
745 callback_do_reboot(NULL, state->window_parent, state);
748 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
749 gpointer data)
751 const gchar *entry_text = NULL;
752 char *str = NULL;
753 struct join_state *state = (struct join_state *)data;
755 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
756 debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
757 if (!entry_text || entry_text[0] == 0) {
758 state->hostname_changed = FALSE;
759 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
760 return;
762 if (strcasecmp(state->my_hostname, entry_text) == 0) {
763 state->hostname_changed = FALSE;
764 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
765 return;
767 state->hostname_changed = TRUE;
768 if (state->name_type_initial == NetSetupDomainName) {
769 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
770 } else {
771 asprintf(&str, "%s.", entry_text);
773 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
774 free(str);
776 if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
777 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
781 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
782 gpointer data)
784 const gchar *entry_text = NULL;
785 struct join_state *state = (struct join_state *)data;
786 int string_unchanged = 0;
788 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
789 debug("callback_enter_computer_description_and_unlock: %s\n",
790 entry_text);
791 #if 0
792 if (!entry_text || entry_text[0] == 0) {
793 string_unchanged = 1;
794 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
795 FALSE);
796 return;
798 #endif
799 if (entry_text && strcasecmp(state->comment, entry_text) == 0) {
800 string_unchanged = 1;
801 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
802 FALSE);
803 return;
806 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
807 SAFE_FREE(state->comment_new);
808 state->comment_new = strdup(entry_text);
813 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
814 gpointer data)
816 const gchar *entry_text = NULL;
817 struct join_state *state = (struct join_state *)data;
819 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
820 debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
821 if (!entry_text || entry_text[0] == 0) {
822 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
823 return;
825 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
826 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
827 return;
829 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
830 SAFE_FREE(state->name_buffer_new);
831 state->name_buffer_new = strdup(entry_text);
832 state->name_type_new = NetSetupWorkgroupName;
835 static void callback_enter_domain_and_unlock(GtkWidget *widget,
836 gpointer data)
838 const gchar *entry_text = NULL;
839 struct join_state *state = (struct join_state *)data;
841 entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
842 debug("callback_enter_domain_and_unlock: %s\n", entry_text);
843 if (!entry_text || entry_text[0] == 0) {
844 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
845 return;
847 if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
848 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
849 return;
851 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
852 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
853 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
854 SAFE_FREE(state->name_buffer_new);
855 state->name_buffer_new = strdup(entry_text);
856 state->name_type_new = NetSetupDomainName;
859 static void callback_apply_continue(GtkWidget *widget,
860 gpointer data)
862 struct join_state *state = (struct join_state *)data;
864 gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
865 g_signal_emit_by_name(state->button_apply, "clicked");
868 static void callback_do_join_workgroup(GtkWidget *widget,
869 gpointer data)
871 struct join_state *state = (struct join_state *)data;
872 debug("callback_do_join_workgroup choosen\n");
873 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
874 gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
875 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
876 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
877 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
878 callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
881 static void callback_do_join_domain(GtkWidget *widget,
882 gpointer data)
884 struct join_state *state = (struct join_state *)data;
885 debug("callback_do_join_domain choosen\n");
886 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
887 gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
888 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
889 callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
892 static void callback_do_getous(GtkWidget *widget,
893 gpointer data)
895 NET_API_STATUS status;
896 uint32_t num_ous = 0;
897 const char **ous = NULL;
898 int i;
899 const char *domain = NULL;
901 struct join_state *state = (struct join_state *)data;
903 debug("callback_do_getous called\n");
905 domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
907 if (!state->account || !state->password) {
908 debug("callback_do_getous: no creds yet\n");
909 callback_creds_prompt(NULL, state,
910 "Enter the name and password of an account with permission to join the domain.",
911 callback_do_storeauth_and_scan);
914 if (!state->account || !state->password) {
915 debug("callback_do_getous: still no creds ???\n");
916 return;
919 status = NetGetJoinableOUs(NULL, domain,
920 state->account,
921 state->password,
922 &num_ous, &ous);
923 if (status != NET_API_STATUS_SUCCESS) {
924 GtkWidget *dialog;
925 callback_do_freeauth(NULL, state);
926 debug("failed to call NetGetJoinableOUs: %s\n",
927 libnetapi_get_error_string(state->ctx, status));
928 dialog = gtk_message_dialog_new(NULL,
929 GTK_DIALOG_DESTROY_WITH_PARENT,
930 GTK_MESSAGE_INFO,
931 GTK_BUTTONS_OK,
932 "Failed to query joinable OUs: %s",
933 libnetapi_get_error_string(state->ctx, status));
934 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
935 gtk_dialog_run(GTK_DIALOG(dialog));
936 gtk_widget_destroy(dialog);
937 return;
940 for (i=0; i<state->stored_num_ous; i++) {
941 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
943 for (i=0; i<num_ous && ous[i] != NULL; i++) {
944 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
945 ous[i]);
947 NetApiBufferFree(ous);
948 state->stored_num_ous = num_ous;
949 gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
952 static void callback_do_change(GtkWidget *widget,
953 gpointer data)
955 GtkWidget *window;
956 GtkWidget *box1;
957 GtkWidget *bbox;
958 GtkWidget *button_workgroup;
959 GtkWidget *button_domain;
960 GtkWidget *button;
961 GtkWidget *label;
962 GtkWidget *frame_horz;
963 GtkWidget *vbox;
964 GtkWidget *entry;
965 GSList *group;
967 struct join_state *state = (struct join_state *)data;
969 debug("callback_do_change called\n");
971 #if 0
972 /* FIXME: add proper warnings for Samba as a DC */
973 if (state->server_role == 3) {
974 GtkWidget *dialog;
975 callback_do_freeauth(NULL, state);
976 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
977 GTK_DIALOG_DESTROY_WITH_PARENT,
978 GTK_MESSAGE_ERROR,
979 GTK_BUTTONS_OK,
980 "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.");
981 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
982 g_signal_connect_swapped(dialog, "response",
983 G_CALLBACK(gtk_widget_destroy),
984 dialog);
986 gtk_widget_show(dialog);
987 return;
989 #endif
991 state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
992 state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
993 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
994 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
996 gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
997 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
998 gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
999 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1001 g_signal_connect(G_OBJECT(window), "delete_event",
1002 G_CALLBACK(callback_do_close), window);
1004 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1006 box1 = gtk_vbox_new(FALSE, 0);
1007 gtk_container_add(GTK_CONTAINER(window), box1);
1009 label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1010 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1011 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1012 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1013 gtk_widget_show(label);
1015 /* COMPUTER NAME */
1016 label = gtk_label_new("Computer name:");
1017 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1018 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1019 gtk_widget_show(label);
1021 state->label_full_computer_name = gtk_label_new(NULL);
1023 entry = gtk_entry_new();
1024 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1025 g_signal_connect(G_OBJECT(entry), "changed",
1026 G_CALLBACK(callback_enter_hostname_and_unlock),
1027 (gpointer)state);
1028 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1029 gtk_editable_select_region(GTK_EDITABLE(entry),
1030 0, GTK_ENTRY(entry)->text_length);
1032 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1033 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1034 gtk_widget_show(entry);
1037 /* FULL COMPUTER NAME */
1038 label = gtk_label_new("Full computer name:");
1039 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1040 gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1041 gtk_widget_show(label);
1044 const gchar *entry_text;
1045 char *str = NULL;
1046 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1047 if (state->name_type_initial == NetSetupDomainName) {
1048 asprintf(&str, "%s.%s", entry_text,
1049 state->my_dnsdomain);
1050 } else {
1051 asprintf(&str, "%s.", entry_text);
1053 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1054 str);
1055 free(str);
1056 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1057 gtk_box_pack_start(GTK_BOX(box1),
1058 state->label_full_computer_name, TRUE, TRUE, 0);
1059 gtk_widget_show(state->label_full_computer_name);
1062 /* BOX */
1063 frame_horz = gtk_frame_new ("Member Of");
1064 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1066 vbox = gtk_vbox_new(FALSE, 0);
1067 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1068 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1070 /* TWO ENTRIES */
1071 state->entry_workgroup = gtk_entry_new();
1072 state->entry_domain = gtk_entry_new();
1074 /* DOMAIN */
1075 button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1076 if (state->name_type_initial == NetSetupDomainName) {
1077 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1079 gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1080 g_signal_connect(G_OBJECT(button_domain), "clicked",
1081 G_CALLBACK(callback_do_join_domain),
1082 (gpointer)state);
1085 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1086 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1087 G_CALLBACK(callback_enter_domain_and_unlock),
1088 (gpointer)state);
1089 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1090 G_CALLBACK(callback_continue),
1091 (gpointer)state);
1092 if (state->name_type_initial == NetSetupDomainName) {
1093 gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1094 state->name_buffer_initial);
1095 gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1096 gtk_widget_set_sensitive(state->entry_domain, TRUE);
1098 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1099 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1100 gtk_widget_show(state->entry_domain);
1102 gtk_widget_show(button_domain);
1104 /* WORKGROUP */
1105 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1106 button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1107 if (state->name_type_initial == NetSetupWorkgroupName) {
1108 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1110 gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1111 g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1112 G_CALLBACK(callback_do_join_workgroup),
1113 (gpointer)state);
1115 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1116 MAX_NETBIOS_NAME_LEN);
1117 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1118 G_CALLBACK(callback_enter_workgroup_and_unlock),
1119 (gpointer)state);
1120 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1121 G_CALLBACK(callback_continue),
1122 (gpointer)state);
1124 if (state->name_type_initial == NetSetupWorkgroupName) {
1125 gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1126 state->name_buffer_initial);
1127 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1128 gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1130 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1131 gtk_widget_show(state->entry_workgroup);
1133 gtk_widget_show(button_workgroup);
1135 /* Advanced Options */
1136 frame_horz = gtk_frame_new("Advanced Options");
1137 gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1139 vbox = gtk_vbox_new(FALSE, 0);
1140 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1141 gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1143 /* OUs */
1144 gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1145 gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1146 g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1147 G_CALLBACK(callback_do_getous),
1148 (gpointer)state);
1150 state->entry_ou_list = gtk_combo_box_entry_new_text();
1151 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1152 if (state->name_type_initial == NetSetupWorkgroupName) {
1153 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1154 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1156 gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1157 gtk_widget_show(state->entry_ou_list);
1160 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1161 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1162 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1166 /* BUTTONS */
1167 bbox = gtk_hbutton_box_new();
1168 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1169 gtk_container_add(GTK_CONTAINER(box1), bbox);
1170 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1171 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1173 state->window_do_change = window;
1174 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1175 gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1176 g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1177 G_CALLBACK(callback_do_join),
1178 (gpointer)state);
1180 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1181 gtk_container_add(GTK_CONTAINER(bbox), button);
1182 g_signal_connect(G_OBJECT(button), "clicked",
1183 G_CALLBACK(callback_do_freeauth_and_close),
1184 (gpointer)state);
1186 gtk_widget_show_all(window);
1189 static void callback_do_about(GtkWidget *widget,
1190 gpointer data)
1192 GdkPixbuf *logo;
1193 GError *error = NULL;
1194 GtkWidget *about;
1196 debug("callback_do_about called\n");
1198 logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1199 &error);
1200 if (logo == NULL) {
1201 g_print("failed to load logo from %s: %s\n",
1202 SAMBA_IMAGE_PATH, error->message);
1205 about = gtk_about_dialog_new();
1206 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1207 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1208 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1209 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1210 "Copyright Günther Deschner 2007-2008");
1211 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1212 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1213 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1214 if (logo) {
1215 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1217 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1218 gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1219 g_signal_connect_swapped(about, "response",
1220 G_CALLBACK(gtk_widget_destroy),
1221 about);
1223 gtk_widget_show(about);
1226 static int draw_main_window(struct join_state *state)
1228 GtkWidget *window;
1229 GtkWidget *button;
1230 GtkWidget *label;
1231 GtkWidget *main_vbox;
1232 GtkWidget *vbox;
1233 GtkWidget *hbox;
1234 GtkWidget *bbox;
1235 GtkWidget *image;
1236 GtkWidget *table;
1237 GtkWidget *entry;
1238 GdkPixbuf *icon;
1239 GError *error = NULL;
1241 icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1242 &error);
1243 if (icon == NULL) {
1244 g_print("failed to load icon from %s : %s\n",
1245 SAMBA_ICON_PATH, error->message);
1248 #if 1
1249 image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1250 #else
1251 image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1252 #endif
1253 if (image == NULL) {
1254 g_print("failed to load logo from %s : %s\n",
1255 SAMBA_IMAGE_PATH_SMALL, error->message);
1258 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1259 state->window_main = window;
1261 gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1262 gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1263 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1264 gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1266 g_signal_connect(G_OBJECT(window), "delete_event",
1267 G_CALLBACK(callback_delete_event), NULL);
1269 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1271 main_vbox = gtk_vbox_new(FALSE, 10);
1272 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1274 #if 0
1275 gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1276 gtk_widget_show(image);
1277 #endif
1278 /* Hbox */
1279 hbox = gtk_hbox_new(FALSE, 10);
1280 gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1283 /* gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1284 /* gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1285 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1286 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1287 gtk_widget_show(image);
1289 /* Label */
1290 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1291 /* gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1292 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1293 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1294 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1295 gtk_widget_show(label);
1298 gtk_widget_show(hbox);
1300 vbox = gtk_vbox_new(FALSE, 0);
1301 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1302 gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1304 /* Table */
1305 table = gtk_table_new(6, 3, TRUE);
1306 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1307 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1308 gtk_container_add(GTK_CONTAINER(vbox), table);
1311 /* Label */
1312 label = gtk_label_new("Computer description:");
1313 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1314 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1315 gtk_widget_show(label);
1317 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1319 /* Entry */
1320 entry = gtk_entry_new();
1321 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1322 g_signal_connect(G_OBJECT(entry), "changed",
1323 G_CALLBACK(callback_enter_computer_description_and_unlock),
1324 state);
1325 g_signal_connect(G_OBJECT(entry), "activate",
1326 G_CALLBACK(callback_apply_continue),
1327 (gpointer)state);
1329 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1330 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1331 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1332 gtk_widget_show(entry);
1335 /* Label */
1336 label = gtk_label_new("For example: \"Samba \%v\".");
1337 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1338 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1339 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1340 gtk_widget_show(label);
1342 /* Label */
1343 label = gtk_label_new("Full computer name:");
1344 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1345 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1346 gtk_widget_show(label);
1349 /* Label */
1350 char *str = NULL;
1351 if (state->name_type_initial == NetSetupDomainName) {
1352 asprintf(&str, "%s.%s", state->my_hostname,
1353 state->my_dnsdomain);
1354 } else {
1355 asprintf(&str, "%s.", state->my_hostname);
1358 label = gtk_label_new(str);
1359 SAFE_FREE(str);
1360 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1361 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1362 gtk_widget_show(label);
1365 /* Label */
1366 if (state->name_type_initial == NetSetupDomainName) {
1367 label = gtk_label_new("Domain:");
1368 } else {
1369 label = gtk_label_new("Workgroup:");
1371 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1372 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1373 gtk_widget_show(label);
1374 state->label_current_name_type = label;
1376 /* Label */
1377 label = gtk_label_new(state->name_buffer_initial);
1378 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1379 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1380 gtk_widget_show(label);
1381 state->label_current_name_buffer = label;
1384 hbox = gtk_hbox_new(FALSE, 0);
1385 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1386 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1387 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1392 /* bbox */
1393 bbox = gtk_hbutton_box_new();
1394 gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1395 gtk_container_add(GTK_CONTAINER(hbox), bbox);
1396 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1397 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1399 button = gtk_button_new_with_mnemonic("Ch_ange");
1400 g_signal_connect(G_OBJECT(button), "clicked",
1401 G_CALLBACK(callback_do_change),
1402 (gpointer)state);
1403 gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1404 gtk_widget_show(button);
1406 /* Label (hidden) */
1407 state->label_reboot = gtk_label_new(NULL);
1408 gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1409 gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1410 gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1411 gtk_widget_show(state->label_reboot);
1413 #if 0
1414 gtk_box_pack_start(GTK_BOX(vbox),
1415 create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1416 TRUE, TRUE, 5);
1417 #endif
1420 GtkWidget *frame;
1421 GtkWidget *bbox2;
1422 GtkWidget *button2;
1424 frame = gtk_frame_new(NULL);
1425 bbox2 = gtk_hbutton_box_new();
1427 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1428 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1430 /* Set the appearance of the Button Box */
1431 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1432 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1433 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1435 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1436 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1437 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1439 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1440 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1441 g_signal_connect(G_OBJECT(button2), "clicked",
1442 G_CALLBACK(callback_delete_event),
1443 window);
1445 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1446 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1447 G_CALLBACK(callback_apply_description_change),
1448 state);
1449 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1451 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1452 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1453 g_signal_connect(G_OBJECT(button2), "clicked",
1454 G_CALLBACK(callback_do_about),
1455 window);
1456 #if 0
1457 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1458 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1459 g_signal_connect(G_OBJECT(button2), "clicked",
1460 G_CALLBACK(callback_do_about),
1461 window);
1462 #endif
1463 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1466 gtk_widget_show_all(window);
1468 return 0;
1471 static int init_join_state(struct join_state **state)
1473 struct join_state *s;
1475 s = malloc(sizeof(struct join_state));
1476 if (!s) {
1477 return -1;
1480 memset(s, '\0', sizeof(struct join_state));
1482 *state = s;
1484 return 0;
1487 static int initialize_join_state(struct join_state *state,
1488 const char *debug_level)
1490 struct libnetapi_ctx *ctx = NULL;
1491 NET_API_STATUS status = 0;
1493 status = libnetapi_init(&ctx);
1494 if (status) {
1495 return status;
1498 if (debug_level) {
1499 libnetapi_set_debuglevel(ctx, debug_level);
1503 char my_hostname[HOST_NAME_MAX];
1504 const char *p = NULL;
1505 struct hostent *hp = NULL;
1507 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1508 return -1;
1511 p = strchr(my_hostname, '.');
1512 if (p) {
1513 my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1515 state->my_hostname = strdup(my_hostname);
1516 if (!state->my_hostname) {
1517 return -1;
1519 debug("state->my_hostname: %s\n", state->my_hostname);
1521 hp = gethostbyname(my_hostname);
1522 if (!hp || !hp->h_name || !*hp->h_name) {
1523 return -1;
1526 state->my_fqdn = strdup(hp->h_name);
1527 if (!state->my_fqdn) {
1528 return -1;
1530 debug("state->my_fqdn: %s\n", state->my_fqdn);
1532 p = strchr(state->my_fqdn, '.');
1533 if (p) {
1534 p++;
1535 state->my_dnsdomain = strdup(p);
1536 } else {
1537 state->my_dnsdomain = strdup("");
1539 if (!state->my_dnsdomain) {
1540 return -1;
1542 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1546 const char *buffer = NULL;
1547 uint16_t type = 0;
1548 status = NetGetJoinInformation(NULL, &buffer, &type);
1549 if (status != 0) {
1550 printf("NetGetJoinInformation failed with: %s\n",
1551 libnetapi_get_error_string(state->ctx, status));
1552 return status;
1554 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1555 state->name_buffer_initial = strdup(buffer);
1556 if (!state->name_buffer_initial) {
1557 return -1;
1559 state->name_type_initial = type;
1560 NetApiBufferFree((void *)buffer);
1564 struct SERVER_INFO_1005 *info1005 = NULL;
1565 uint8_t *buffer = NULL;
1567 status = NetServerGetInfo(NULL, 1005, &buffer);
1568 if (status != 0) {
1569 printf("NetServerGetInfo failed with: %s\n",
1570 libnetapi_get_error_string(state->ctx, status));
1571 return status;
1574 info1005 = (struct SERVER_INFO_1005 *)buffer;
1576 state->comment = strdup(info1005->sv1005_comment);
1577 if (!state->comment) {
1578 return -1;
1580 NetApiBufferFree(buffer);
1582 #if 0
1584 struct srvsvc_NetSrvInfo100 *info100 = NULL;
1585 uint8_t *buffer = NULL;
1587 status = NetServerGetInfo(NULL, 100, &buffer);
1588 if (status) {
1589 return status;
1592 info100 = (struct srvsvc_NetSrvInfo100 *)buffer;
1594 state->comment = strdup(info100->comment);
1595 if (!state->comment) {
1596 return -1;
1599 #endif
1601 state->ctx = ctx;
1603 return 0;
1606 int main(int argc, char **argv)
1608 GOptionContext *context = NULL;
1609 static const char *debug_level = NULL;
1610 struct join_state *state = NULL;
1611 GError *error = NULL;
1612 int ret = 0;
1614 static GOptionEntry entries[] = {
1615 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1616 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1617 { NULL }
1620 context = g_option_context_new("- Samba domain join utility");
1621 g_option_context_add_main_entries(context, entries, NULL);
1622 /* g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1623 g_option_context_add_group(context, gtk_get_option_group(TRUE));
1624 g_option_context_parse(context, &argc, &argv, &error);
1626 gtk_init(&argc, &argv);
1627 g_set_application_name("Samba");
1629 ret = init_join_state(&state);
1630 if (ret) {
1631 return ret;
1634 ret = initialize_join_state(state, debug_level);
1635 if (ret) {
1636 return ret;
1639 draw_main_window(state);
1641 gtk_main();
1643 do_cleanup(state);
1645 return 0;