• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source3/lib/netapi/examples/netdomjoin-gui/
1/*
2 *  Unix SMB/CIFS implementation.
3 *  Join Support (gtk + netapi)
4 *  Copyright (C) Guenther Deschner 2007-2008
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
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>
28
29#include <gtk/gtk.h>
30#include <glib/gprintf.h>
31
32#include <netapi.h>
33
34#define MAX_CRED_LEN 256
35#define MAX_NETBIOS_NAME_LEN 15
36
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"
40
41#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
42
43static gboolean verbose = FALSE;
44
45typedef struct join_state {
46	struct libnetapi_ctx *ctx;
47	GtkWidget *window_main;
48	GtkWidget *window_parent;
49	GtkWidget *window_do_change;
50	GtkWidget *window_creds_prompt;
51	GtkWidget *entry_account;
52	GtkWidget *entry_password;
53	GtkWidget *entry_domain;
54	GtkWidget *entry_ou_list;
55	GtkWidget *entry_workgroup;
56	GtkWidget *button_ok;
57	GtkWidget *button_apply;
58	GtkWidget *button_ok_creds;
59	GtkWidget *button_get_ous;
60	GtkWidget *label_reboot;
61	GtkWidget *label_current_name_buffer;
62	GtkWidget *label_current_name_type;
63	GtkWidget *label_full_computer_name;
64	GtkWidget *label_winbind;
65	uint16_t name_type_initial;
66	uint16_t name_type_new;
67	char *name_buffer_initial;
68	char *name_buffer_new;
69	char *password;
70	char *account;
71	char *comment;
72	char *comment_new;
73	char *my_fqdn;
74	char *my_dnsdomain;
75	char *my_hostname;
76	uint16_t server_role;
77	gboolean settings_changed;
78	gboolean hostname_changed;
79	uint32_t stored_num_ous;
80	char *target_hostname;
81	uid_t uid;
82} join_state;
83
84static void callback_creds_prompt(GtkWidget *widget,
85				  gpointer data,
86				  const char *label_string,
87				  gpointer cont_fn);
88
89
90static void debug(const char *format, ...)
91{
92	va_list args;
93
94	if (!verbose) {
95		return;
96	}
97
98	va_start(args, format);
99	g_vprintf(format, args);
100	va_end(args);
101}
102
103static gboolean callback_delete_event(GtkWidget *widget,
104				      GdkEvent *event,
105				      gpointer data)
106{
107	gtk_main_quit();
108	return FALSE;
109}
110
111static void callback_do_close_data(GtkWidget *widget,
112				   gpointer data)
113{
114	debug("callback_do_close_data called\n");
115
116	if (data) {
117		gtk_widget_destroy(GTK_WIDGET(data));
118	}
119}
120
121static void callback_do_close_widget(GtkWidget *widget,
122				     gpointer data)
123{
124	debug("callback_do_close_widget called\n");
125
126	if (widget) {
127		gtk_widget_destroy(widget);
128	}
129}
130
131static void callback_do_freeauth(GtkWidget *widget,
132				 gpointer data)
133{
134	struct join_state *state = (struct join_state *)data;
135
136	debug("callback_do_freeauth called\n");
137
138	SAFE_FREE(state->account);
139	SAFE_FREE(state->password);
140
141	if (state->window_creds_prompt) {
142		gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
143		state->window_creds_prompt = NULL;
144	}
145}
146
147static void callback_do_freeauth_and_close(GtkWidget *widget,
148					   gpointer data)
149{
150	struct join_state *state = (struct join_state *)data;
151
152	debug("callback_do_freeauth_and_close called\n");
153
154	SAFE_FREE(state->account);
155	SAFE_FREE(state->password);
156
157	if (state->window_creds_prompt) {
158		gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
159		state->window_creds_prompt = NULL;
160	}
161	if (state->window_do_change) {
162		gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
163		state->window_do_change = NULL;
164	}
165}
166
167static void free_join_state(struct join_state *s)
168{
169	SAFE_FREE(s->name_buffer_initial);
170	SAFE_FREE(s->name_buffer_new);
171	SAFE_FREE(s->password);
172	SAFE_FREE(s->account);
173	SAFE_FREE(s->comment);
174	SAFE_FREE(s->comment_new);
175	SAFE_FREE(s->my_fqdn);
176	SAFE_FREE(s->my_dnsdomain);
177	SAFE_FREE(s->my_hostname);
178}
179
180static void do_cleanup(struct join_state *state)
181{
182	libnetapi_free(state->ctx);
183	free_join_state(state);
184}
185
186static void callback_apply_description_change(GtkWidget *widget,
187					      gpointer data)
188{
189	struct join_state *state = (struct join_state *)data;
190	NET_API_STATUS status = 0;
191	uint32_t parm_err = 0;
192	struct SERVER_INFO_1005 info1005;
193	GtkWidget *dialog;
194
195	info1005.sv1005_comment = state->comment_new;
196
197	status = NetServerSetInfo(state->target_hostname,
198				  1005,
199				  (uint8_t *)&info1005,
200				  &parm_err);
201	if (status) {
202		debug("NetServerSetInfo failed with: %s\n",
203			libnetapi_errstr(status));
204		dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
205						GTK_DIALOG_DESTROY_WITH_PARENT,
206						GTK_MESSAGE_ERROR,
207						GTK_BUTTONS_OK,
208						"Failed to change computer description: %s.",
209						libnetapi_get_error_string(state->ctx, status));
210		gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
211		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
212
213		g_signal_connect_swapped(dialog, "response",
214					 G_CALLBACK(gtk_widget_destroy),
215					 dialog);
216
217		gtk_widget_show(dialog);
218		return;
219	}
220
221	gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
222}
223
224static void callback_do_exit(GtkWidget *widget,
225			     gpointer data)
226{
227#if 0
228	GtkWidget *dialog;
229	gint result;
230#endif
231	struct join_state *state = (struct join_state *)data;
232
233	if (!state->settings_changed) {
234		callback_delete_event(NULL, NULL, NULL);
235		return;
236	}
237
238#if 0
239	dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
240					GTK_DIALOG_DESTROY_WITH_PARENT,
241					GTK_MESSAGE_QUESTION,
242					GTK_BUTTONS_YES_NO,
243					"You must restart your computer before the new settings will take effect.");
244	gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
245	result = gtk_dialog_run(GTK_DIALOG(dialog));
246	switch (result) {
247		case GTK_RESPONSE_YES:
248			g_print("would reboot here\n");
249			break;
250		case GTK_RESPONSE_NO:
251		default:
252			break;
253	}
254	if (dialog) {
255		gtk_widget_destroy(GTK_WIDGET(dialog));
256	}
257#endif
258	if (state->window_main) {
259		gtk_widget_destroy(GTK_WIDGET(state->window_main));
260		state->window_main = NULL;
261	}
262	do_cleanup(state);
263	exit(0);
264}
265
266
267static void callback_do_reboot(GtkWidget *widget,
268			       gpointer data,
269			       gpointer data2)
270{
271	GtkWidget *dialog;
272	struct join_state *state = (struct join_state *)data2;
273
274	debug("callback_do_reboot\n");
275
276	state->settings_changed = TRUE;
277	dialog = gtk_message_dialog_new(GTK_WINDOW(data),
278					GTK_DIALOG_DESTROY_WITH_PARENT,
279					GTK_MESSAGE_INFO,
280					GTK_BUTTONS_OK,
281					"You must restart this computer for the changes to take effect.");
282	gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
283	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
284#if 0
285	g_signal_connect_swapped(dialog, "response",
286				 G_CALLBACK(gtk_widget_destroy),
287				 dialog);
288
289	debug("showing dialog\n");
290	gtk_widget_show(dialog);
291#else
292	gtk_dialog_run(GTK_DIALOG(dialog));
293	gtk_widget_destroy(GTK_WIDGET(dialog));
294#endif
295
296	gtk_label_set_text(GTK_LABEL(state->label_reboot),
297			   "Changes will take effect after you restart this computer");
298
299	debug("destroying do_change window\n");
300	gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
301
302	{
303		uint32_t status;
304		const char *buffer;
305		uint16_t type;
306
307		status = NetGetJoinInformation(state->target_hostname,
308					       &buffer,
309					       &type);
310		if (status != 0) {
311			g_print("failed to query status\n");
312			return;
313		}
314
315		debug("got new status: %s\n", buffer);
316
317		SAFE_FREE(state->name_buffer_new);
318		state->name_buffer_new = strdup(buffer);
319		state->name_type_new = type;
320		state->name_buffer_initial = strdup(buffer);
321		state->name_type_initial = type;
322		NetApiBufferFree((void *)buffer);
323
324		gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer),
325				   state->name_buffer_new);
326		if (state->name_type_new == NetSetupDomainName) {
327			gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
328					   "Domain:");
329		} else {
330			gtk_label_set_text(GTK_LABEL(state->label_current_name_type),
331					   "Workgroup:");
332		}
333	}
334}
335
336static void callback_return_username(GtkWidget *widget,
337				     gpointer data)
338{
339	const gchar *entry_text;
340	struct join_state *state = (struct join_state *)data;
341	debug("callback_return_username called\n");
342	if (!widget) {
343		return;
344	}
345	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
346	if (!entry_text) {
347		return;
348	}
349	debug("callback_return_username: %s\n", entry_text);
350	SAFE_FREE(state->account);
351	state->account = strdup(entry_text);
352}
353
354static void callback_return_username_and_enter(GtkWidget *widget,
355					       gpointer data)
356{
357	const gchar *entry_text;
358	struct join_state *state = (struct join_state *)data;
359	if (!widget) {
360		return;
361	}
362	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
363	if (!entry_text) {
364		return;
365	}
366	debug("callback_return_username_and_enter: %s\n", entry_text);
367	SAFE_FREE(state->account);
368	state->account = strdup(entry_text);
369	g_signal_emit_by_name(state->button_ok_creds, "clicked");
370}
371
372static void callback_return_password(GtkWidget *widget,
373				     gpointer data)
374{
375	const gchar *entry_text;
376	struct join_state *state = (struct join_state *)data;
377	debug("callback_return_password called\n");
378	if (!widget) {
379		return;
380	}
381	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
382	if (!entry_text) {
383		return;
384	}
385#ifdef DEBUG_PASSWORD
386	debug("callback_return_password: %s\n", entry_text);
387#else
388	debug("callback_return_password: (not printed)\n");
389#endif
390	SAFE_FREE(state->password);
391	state->password = strdup(entry_text);
392}
393
394static void callback_return_password_and_enter(GtkWidget *widget,
395					       gpointer data)
396{
397	const gchar *entry_text;
398	struct join_state *state = (struct join_state *)data;
399	if (!widget) {
400		return;
401	}
402	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
403	if (!entry_text) {
404		return;
405	}
406#ifdef DEBUG_PASSWORD
407	debug("callback_return_password_and_enter: %s\n", entry_text);
408#else
409	debug("callback_return_password_and_enter: (not printed)\n");
410#endif
411	SAFE_FREE(state->password);
412	state->password = strdup(entry_text);
413	g_signal_emit_by_name(state->button_ok_creds, "clicked");
414}
415
416static void callback_do_storeauth(GtkWidget *widget,
417				  gpointer data)
418{
419	struct join_state *state = (struct join_state *)data;
420
421	debug("callback_do_storeauth called\n");
422
423	SAFE_FREE(state->account);
424	SAFE_FREE(state->password);
425
426	callback_return_username(state->entry_account, (gpointer)state);
427	callback_return_password(state->entry_password, (gpointer)state);
428
429	if (state->window_creds_prompt) {
430		gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
431		state->window_creds_prompt = NULL;
432	}
433}
434
435static void callback_continue(GtkWidget *widget,
436			      gpointer data)
437{
438	struct join_state *state = (struct join_state *)data;
439
440	gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
441	g_signal_emit_by_name(state->button_ok, "clicked");
442}
443
444static void callback_do_storeauth_and_continue(GtkWidget *widget,
445					       gpointer data)
446{
447	callback_do_storeauth(widget, data);
448	callback_continue(NULL, data);
449}
450
451static void callback_do_storeauth_and_scan(GtkWidget *widget,
452					   gpointer data)
453{
454	struct join_state *state = (struct join_state *)data;
455	callback_do_storeauth(widget, data);
456	g_signal_emit_by_name(state->button_get_ous, "clicked");
457}
458
459static void callback_do_hostname_change(GtkWidget *widget,
460					gpointer data)
461{
462	GtkWidget *dialog;
463	const char *str = NULL;
464
465	struct join_state *state = (struct join_state *)data;
466
467	switch (state->name_type_initial) {
468		case NetSetupDomainName: {
469#if 0
470			NET_API_STATUS status;
471			const char *newname;
472			char *p = NULL;
473
474			newname = strdup(gtk_label_get_text(GTK_LABEL(state->label_full_computer_name)));
475			if (!newname) {
476				return;
477			}
478
479			p = strchr(newname, '.');
480			if (p) {
481				*p = NULL;
482			}
483
484			if (!state->account || !state->password) {
485				debug("callback_do_hostname_change: no creds yet\n");
486				callback_creds_prompt(NULL, state,
487						      "Enter the name and password of an account with permission to change a computer name in a the domain.",
488						      callback_do_storeauth_and_continue);
489			}
490
491			if (!state->account || !state->password) {
492				debug("callback_do_hostname_change: still no creds???\n");
493				return;
494			}
495
496			status = NetRenameMachineInDomain(state->target_hostname,
497							  newname,
498							  state->account,
499							  state->password,
500							  NETSETUP_ACCT_CREATE);
501			SAFE_FREE(newname);
502			/* we renamed the machine in the domain */
503			if (status == 0) {
504				return;
505			}
506			str = libnetapi_get_error_string(state->ctx, status);
507#else
508			str = "To be implemented: call NetRenameMachineInDomain\n";
509#endif
510			break;
511		}
512		case NetSetupWorkgroupName:
513			str = "To be implemented: call SetComputerNameEx\n";
514			break;
515		default:
516			break;
517	}
518
519	dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
520					GTK_DIALOG_DESTROY_WITH_PARENT,
521					GTK_MESSAGE_ERROR,
522					GTK_BUTTONS_CLOSE,
523					"%s",str);
524
525	gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
526	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_main));
527	g_signal_connect_swapped(dialog, "response",
528				 G_CALLBACK(gtk_widget_destroy),
529				 dialog);
530	gtk_widget_show(dialog);
531}
532
533static void callback_creds_prompt(GtkWidget *widget,
534				  gpointer data,
535				  const char *label_string,
536				  gpointer cont_fn)
537{
538	GtkWidget *window;
539	GtkWidget *box1;
540	GtkWidget *bbox;
541	GtkWidget *button;
542	GtkWidget *label;
543
544	struct join_state *state = (struct join_state *)data;
545
546	debug("callback_creds_prompt\n");
547
548	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
549	gtk_window_set_modal(GTK_WINDOW(window), TRUE);
550
551	gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
552	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
553	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
554	gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
555	gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
556	gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_do_change));
557	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
558
559	g_signal_connect(G_OBJECT(window), "delete_event",
560			 G_CALLBACK(callback_do_close_widget), NULL);
561
562	state->window_creds_prompt = window;
563	gtk_container_set_border_width(GTK_CONTAINER(window), 10);
564
565	box1 = gtk_vbox_new(FALSE, 0);
566
567	gtk_container_add(GTK_CONTAINER(window), box1);
568
569	label = gtk_label_new(label_string);
570	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
571	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
572
573	gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
574
575	gtk_widget_show(label);
576
577	/* USER NAME */
578	label = gtk_label_new("User name:");
579	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
580	gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
581	gtk_widget_show(label);
582
583	state->entry_account = gtk_entry_new();
584	gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
585	g_signal_connect(G_OBJECT(state->entry_account), "activate",
586			 G_CALLBACK(callback_return_username_and_enter),
587			 (gpointer)state);
588	gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
589				   0, GTK_ENTRY(state->entry_account)->text_length);
590	gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
591	gtk_widget_show(state->entry_account);
592
593	/* PASSWORD */
594	label = gtk_label_new("Password:");
595	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
596	gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
597	gtk_widget_show(label);
598
599	state->entry_password = gtk_entry_new();
600	gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
601	gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
602	g_signal_connect(G_OBJECT(state->entry_password), "activate",
603			 G_CALLBACK(callback_return_password_and_enter),
604			 (gpointer)state);
605	gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
606	gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
607				   0, GTK_ENTRY(state->entry_password)->text_length);
608	gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
609	gtk_widget_show(state->entry_password);
610
611	/* BUTTONS */
612	bbox = gtk_hbutton_box_new();
613	gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
614	gtk_container_add(GTK_CONTAINER(box1), bbox);
615	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
616	gtk_box_set_spacing(GTK_BOX(bbox), 10);
617
618	state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
619	gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
620	gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
621	g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
622			 G_CALLBACK(cont_fn),
623			 (gpointer)state);
624	gtk_widget_show(state->button_ok_creds);
625
626	button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
627	gtk_container_add(GTK_CONTAINER(bbox), button);
628	g_signal_connect(G_OBJECT(button), "clicked",
629			 G_CALLBACK(callback_do_freeauth),
630			 (gpointer)state);
631	gtk_widget_show_all(window);
632}
633
634static void callback_do_join(GtkWidget *widget,
635			     gpointer data)
636{
637	GtkWidget *dialog;
638
639	NET_API_STATUS status;
640	const char *err_str = NULL;
641	uint32_t join_flags = 0;
642	uint32_t unjoin_flags = 0;
643	gboolean domain_join = FALSE;
644	gboolean try_unjoin = FALSE;
645	gboolean join_creds_required = TRUE;
646	gboolean unjoin_creds_required = TRUE;
647	const char *new_workgroup_type = NULL;
648	const char *initial_workgroup_type = NULL;
649	const char *account_ou = NULL;
650
651	struct join_state *state = (struct join_state *)data;
652
653	if (state->hostname_changed) {
654		callback_do_hostname_change(NULL, state);
655		return;
656	}
657
658	switch (state->name_type_initial) {
659		case NetSetupWorkgroupName:
660			initial_workgroup_type = "workgroup";
661			break;
662		case NetSetupDomainName:
663			initial_workgroup_type = "domain";
664			break;
665		default:
666			break;
667	}
668
669	switch (state->name_type_new) {
670		case NetSetupWorkgroupName:
671			new_workgroup_type = "workgroup";
672			break;
673		case NetSetupDomainName:
674			new_workgroup_type = "domain";
675			break;
676		default:
677			break;
678	}
679
680	account_ou = gtk_combo_box_get_active_text(GTK_COMBO_BOX(state->entry_ou_list));
681	if (account_ou && strlen(account_ou) == 0) {
682		account_ou = NULL;
683	}
684
685	if ((state->name_type_initial != NetSetupDomainName) &&
686	    (state->name_type_new != NetSetupDomainName)) {
687		join_creds_required = FALSE;
688		unjoin_creds_required = FALSE;
689	}
690
691	if (state->name_type_new == NetSetupDomainName) {
692		domain_join = TRUE;
693		join_creds_required = TRUE;
694		join_flags = NETSETUP_JOIN_DOMAIN |
695			     NETSETUP_ACCT_CREATE |
696			     NETSETUP_DOMAIN_JOIN_IF_JOINED; /* for testing */
697	}
698
699	if ((state->name_type_initial == NetSetupDomainName) &&
700	    (state->name_type_new == NetSetupWorkgroupName)) {
701		try_unjoin = TRUE;
702		unjoin_creds_required = TRUE;
703		join_creds_required = FALSE;
704		unjoin_flags = NETSETUP_JOIN_DOMAIN |
705			       NETSETUP_ACCT_DELETE |
706			       NETSETUP_IGNORE_UNSUPPORTED_FLAGS;
707	}
708
709	if (try_unjoin) {
710
711		debug("callback_do_join: Unjoining\n");
712
713		if (unjoin_creds_required) {
714			if (!state->account || !state->password) {
715				debug("callback_do_join: no creds yet\n");
716				callback_creds_prompt(NULL, state,
717						      "Enter the name and password of an account with permission to leave the domain.",
718						      callback_do_storeauth_and_continue);
719			}
720
721			if (!state->account || !state->password) {
722				debug("callback_do_join: still no creds???\n");
723				return;
724			}
725		}
726
727		status = NetUnjoinDomain(state->target_hostname,
728					 state->account,
729					 state->password,
730					 unjoin_flags);
731		if (status != 0) {
732			callback_do_freeauth(NULL, state);
733			err_str = libnetapi_get_error_string(state->ctx, status);
734			g_print("callback_do_join: failed to unjoin (%s)\n",
735				err_str);
736#if 0
737
738	/* in fact we shouldn't annoy the user with an error message here */
739
740			dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
741							GTK_DIALOG_DESTROY_WITH_PARENT,
742							GTK_MESSAGE_ERROR,
743							GTK_BUTTONS_CLOSE,
744							"The following error occured attempting to unjoin the %s: \"%s\": %s",
745							initial_workgroup_type,
746							state->name_buffer_initial,
747							err_str);
748			gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
749			gtk_dialog_run(GTK_DIALOG(dialog));
750			gtk_widget_destroy(dialog);
751#endif
752		}
753
754	}
755
756	/* before prompting for creds, make sure we can find a dc */
757
758	if (domain_join) {
759
760		struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
761
762		status = DsGetDcName(NULL,
763				     state->name_buffer_new,
764				     NULL,
765				     NULL,
766				     0,
767				     &dc_info);
768		if (status != 0) {
769			err_str = libnetapi_get_error_string(state->ctx, status);
770			g_print("callback_do_join: failed find dc (%s)\n", err_str);
771
772			dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
773							GTK_DIALOG_DESTROY_WITH_PARENT,
774							GTK_MESSAGE_ERROR,
775							GTK_BUTTONS_CLOSE,
776							"Failed to find a domain controller for domain: \"%s\": %s",
777							state->name_buffer_new,
778							err_str);
779
780			gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
781			gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
782			g_signal_connect_swapped(dialog, "response",
783						 G_CALLBACK(gtk_widget_destroy),
784						 dialog);
785
786			gtk_widget_show(dialog);
787
788			return;
789		}
790	}
791
792	if (join_creds_required) {
793		if (!state->account || !state->password) {
794			debug("callback_do_join: no creds yet\n");
795			callback_creds_prompt(NULL, state,
796					      "Enter the name and password of an account with permission to join the domain.",
797					      callback_do_storeauth_and_continue);
798		}
799
800		if (!state->account || !state->password) {
801			debug("callback_do_join: still no creds???\n");
802			return;
803		}
804	}
805
806	debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
807		new_workgroup_type,
808		state->name_buffer_new,
809		join_flags);
810	if (domain_join) {
811		debug("as %s ", state->account);
812#ifdef DEBUG_PASSWORD
813		debug("with %s ", state->password);
814#endif
815	}
816	debug("\n");
817
818	status = NetJoinDomain(state->target_hostname,
819			       state->name_buffer_new,
820			       account_ou,
821			       state->account,
822			       state->password,
823			       join_flags);
824	if (status != 0) {
825		callback_do_freeauth(NULL, state);
826		err_str = libnetapi_get_error_string(state->ctx, status);
827		g_print("callback_do_join: failed to join (%s)\n", err_str);
828
829		dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
830						GTK_DIALOG_DESTROY_WITH_PARENT,
831						GTK_MESSAGE_ERROR,
832						GTK_BUTTONS_CLOSE,
833						"The following error occured attempting to join the %s: \"%s\": %s",
834						new_workgroup_type,
835						state->name_buffer_new,
836						err_str);
837
838		gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
839		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
840		g_signal_connect_swapped(dialog, "response",
841					 G_CALLBACK(gtk_widget_destroy),
842					 dialog);
843
844		gtk_widget_show(dialog);
845
846		return;
847	}
848
849	debug("callback_do_join: Successfully joined %s\n",
850		new_workgroup_type);
851
852	callback_do_freeauth(NULL, state);
853	dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
854					GTK_DIALOG_DESTROY_WITH_PARENT,
855					GTK_MESSAGE_INFO,
856					GTK_BUTTONS_OK,
857					"Welcome to the %s %s.",
858					state->name_buffer_new,
859					new_workgroup_type);
860
861	gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
862	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
863	gtk_dialog_run(GTK_DIALOG(dialog));
864	gtk_widget_destroy(dialog);
865
866	callback_do_reboot(NULL, state->window_parent, state);
867}
868
869static void callback_enter_hostname_and_unlock(GtkWidget *widget,
870					       gpointer data)
871{
872	const gchar *entry_text = NULL;
873	char *str = NULL;
874	struct join_state *state = (struct join_state *)data;
875
876	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
877	debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
878	if (!entry_text || entry_text[0] == 0) {
879		state->hostname_changed = FALSE;
880		gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
881		gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), "");
882		return;
883	}
884	if (strcasecmp(state->my_hostname, entry_text) == 0) {
885		state->hostname_changed = FALSE;
886		gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
887		/* return; */
888	} else {
889		state->hostname_changed = TRUE;
890	}
891
892	if (state->name_type_initial == NetSetupDomainName) {
893		if (asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain) == -1) {
894			return;
895		}
896	} else {
897		if (asprintf(&str, "%s.", entry_text) == -1) {
898			return;
899		}
900	}
901	gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
902	free(str);
903
904	if (state->hostname_changed && entry_text && entry_text[0] != 0 && entry_text[0] != '.') {
905		gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
906	}
907}
908
909static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
910							   gpointer data)
911{
912	const gchar *entry_text = NULL;
913	struct join_state *state = (struct join_state *)data;
914	int string_unchanged = FALSE;
915
916	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
917	debug("callback_enter_computer_description_and_unlock: %s\n",
918		entry_text);
919#if 0
920	if (!entry_text || entry_text[0] == 0) {
921		string_unchanged = 1;
922		gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
923					 FALSE);
924		return;
925	}
926#endif
927	if (entry_text && state->comment && strcasecmp(state->comment, entry_text) == 0) {
928		string_unchanged = TRUE;
929		gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
930					 FALSE);
931		return;
932	}
933
934	gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
935	SAFE_FREE(state->comment_new);
936	state->comment_new = strdup(entry_text);
937
938}
939
940
941static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
942						gpointer data)
943{
944	const gchar *entry_text = NULL;
945	struct join_state *state = (struct join_state *)data;
946
947	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
948	debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
949	if (!entry_text || entry_text[0] == 0) {
950		gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
951		return;
952	}
953	if ((strcasecmp(state->name_buffer_initial, entry_text) == 0) &&
954	    (state->name_type_initial == NetSetupWorkgroupName)) {
955		gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
956		return;
957	}
958	gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
959	SAFE_FREE(state->name_buffer_new);
960	state->name_buffer_new = strdup(entry_text);
961	state->name_type_new = NetSetupWorkgroupName;
962}
963
964static void callback_enter_domain_and_unlock(GtkWidget *widget,
965					     gpointer data)
966{
967	const gchar *entry_text = NULL;
968	struct join_state *state = (struct join_state *)data;
969
970	entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
971	debug("callback_enter_domain_and_unlock: %s\n", entry_text);
972	if (!entry_text || entry_text[0] == 0) {
973		gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
974		return;
975	}
976	if ((strcasecmp(state->name_buffer_initial, entry_text) == 0) &&
977	    (state->name_type_initial == NetSetupDomainName)) {
978		gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
979		return;
980	}
981	gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
982	gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
983	gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
984	SAFE_FREE(state->name_buffer_new);
985	state->name_buffer_new = strdup(entry_text);
986	state->name_type_new = NetSetupDomainName;
987}
988
989static void callback_apply_continue(GtkWidget *widget,
990				    gpointer data)
991{
992	struct join_state *state = (struct join_state *)data;
993
994	gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
995	g_signal_emit_by_name(state->button_apply, "clicked");
996}
997
998static void callback_do_join_workgroup(GtkWidget *widget,
999				       gpointer data)
1000{
1001	struct join_state *state = (struct join_state *)data;
1002	debug("callback_do_join_workgroup choosen\n");
1003	gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1004	gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
1005	gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1006	gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
1007	gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1008	callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
1009}
1010
1011static void callback_do_join_domain(GtkWidget *widget,
1012				    gpointer data)
1013{
1014	struct join_state *state = (struct join_state *)data;
1015	debug("callback_do_join_domain choosen\n");
1016	gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
1017	gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
1018	gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
1019	callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
1020}
1021
1022static void callback_do_getous(GtkWidget *widget,
1023			       gpointer data)
1024{
1025	NET_API_STATUS status;
1026	uint32_t num_ous = 0;
1027	const char **ous = NULL;
1028	int i;
1029	const char *domain = NULL;
1030	struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
1031	const char *err_str = NULL;
1032	GtkWidget *dialog;
1033
1034	struct join_state *state = (struct join_state *)data;
1035
1036	debug("callback_do_getous called\n");
1037
1038	domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
1039
1040	status = DsGetDcName(NULL,
1041			     domain,
1042			     NULL,
1043			     NULL,
1044			     0,
1045			     &dc_info);
1046	if (status != 0) {
1047		err_str = libnetapi_get_error_string(state->ctx, status);
1048		g_print("callback_do_getous: failed find dc (%s)\n", err_str);
1049
1050		dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
1051						GTK_DIALOG_DESTROY_WITH_PARENT,
1052						GTK_MESSAGE_ERROR,
1053						GTK_BUTTONS_CLOSE,
1054						"Failed to find a domain controller for domain: \"%s\": %s",
1055						domain,
1056						err_str);
1057
1058		gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1059		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1060		g_signal_connect_swapped(dialog, "response",
1061					 G_CALLBACK(gtk_widget_destroy),
1062					 dialog);
1063
1064		gtk_widget_show(dialog);
1065
1066		return;
1067	}
1068
1069	if (!state->account || !state->password) {
1070		debug("callback_do_getous: no creds yet\n");
1071		callback_creds_prompt(NULL, state,
1072				      "Enter the name and password of an account with permission to join the domain.",
1073				      callback_do_storeauth_and_scan);
1074	}
1075
1076	if (!state->account || !state->password) {
1077		debug("callback_do_getous: still no creds ???\n");
1078		return;
1079	}
1080
1081	status = NetGetJoinableOUs(state->target_hostname,
1082				   domain,
1083				   state->account,
1084				   state->password,
1085				   &num_ous, &ous);
1086	if (status != NET_API_STATUS_SUCCESS) {
1087		callback_do_freeauth(NULL, state);
1088		debug("failed to call NetGetJoinableOUs: %s\n",
1089			libnetapi_get_error_string(state->ctx, status));
1090		dialog = gtk_message_dialog_new(NULL,
1091						GTK_DIALOG_DESTROY_WITH_PARENT,
1092						GTK_MESSAGE_INFO,
1093						GTK_BUTTONS_OK,
1094						"Failed to query joinable OUs: %s",
1095						libnetapi_get_error_string(state->ctx, status));
1096		gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1097		gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1098		gtk_dialog_run(GTK_DIALOG(dialog));
1099		gtk_widget_destroy(dialog);
1100		return;
1101	}
1102
1103	for (i=0; i<state->stored_num_ous; i++) {
1104		gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1105	}
1106	for (i=0; i<num_ous && ous[i] != NULL; i++) {
1107		gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1108					  ous[i]);
1109	}
1110	NetApiBufferFree(ous);
1111	state->stored_num_ous = num_ous;
1112	gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1113}
1114
1115static void callback_do_change(GtkWidget *widget,
1116			       gpointer data)
1117{
1118	GtkWidget *window;
1119	GtkWidget *box1;
1120	GtkWidget *bbox;
1121	GtkWidget *button_workgroup;
1122	GtkWidget *button_domain;
1123	GtkWidget *button;
1124	GtkWidget *label;
1125	GtkWidget *frame_horz;
1126	GtkWidget *vbox;
1127	GtkWidget *entry;
1128	GSList *group;
1129
1130	struct join_state *state = (struct join_state *)data;
1131
1132	debug("callback_do_change called\n");
1133
1134#if 0
1135	/* FIXME: add proper warnings for Samba as a DC */
1136	if (state->server_role == 3) {
1137		GtkWidget *dialog;
1138		callback_do_freeauth(NULL, state);
1139		dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1140						GTK_DIALOG_DESTROY_WITH_PARENT,
1141						GTK_MESSAGE_ERROR,
1142						GTK_BUTTONS_OK,
1143						"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.");
1144		gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1145		g_signal_connect_swapped(dialog, "response",
1146					 G_CALLBACK(gtk_widget_destroy),
1147					 dialog);
1148
1149		gtk_widget_show(dialog);
1150		return;
1151	}
1152#endif
1153
1154	state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1155	state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1156	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1157	gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1158
1159	gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1160	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1161	gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1162	gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1163	gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
1164	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1165
1166	g_signal_connect(G_OBJECT(window), "delete_event",
1167			 G_CALLBACK(callback_do_close_widget), NULL);
1168
1169	gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1170
1171	box1 = gtk_vbox_new(FALSE, 0);
1172	gtk_container_add(GTK_CONTAINER(window), box1);
1173
1174	label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1175	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1176	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1177	gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1178	gtk_widget_show(label);
1179
1180	/* COMPUTER NAME */
1181	label = gtk_label_new("Computer name:");
1182	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1183	gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1184	gtk_widget_show(label);
1185
1186	state->label_full_computer_name = gtk_label_new(NULL);
1187	{
1188		entry = gtk_entry_new();
1189		gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1190		g_signal_connect(G_OBJECT(entry), "changed",
1191				 G_CALLBACK(callback_enter_hostname_and_unlock),
1192				 (gpointer)state);
1193		gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1194		gtk_editable_select_region(GTK_EDITABLE(entry),
1195					   0, GTK_ENTRY(entry)->text_length);
1196
1197		gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1198		gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1199		gtk_widget_show(entry);
1200	}
1201
1202	/* FULL COMPUTER NAME */
1203	label = gtk_label_new("Full computer name:");
1204	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1205	gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1206	gtk_widget_show(label);
1207
1208	{
1209		const gchar *entry_text;
1210		char *str = NULL;
1211		entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1212		if (state->name_type_initial == NetSetupDomainName) {
1213			if (asprintf(&str, "%s.%s", entry_text,
1214				 state->my_dnsdomain) == -1) {
1215				return;
1216			}
1217		} else {
1218			if (asprintf(&str, "%s.", entry_text) == -1) {
1219				return;
1220			}
1221		}
1222		gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1223				   str);
1224		free(str);
1225		gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1226		gtk_box_pack_start(GTK_BOX(box1),
1227				   state->label_full_computer_name, TRUE, TRUE, 0);
1228		gtk_widget_show(state->label_full_computer_name);
1229	}
1230
1231	/* BOX */
1232	frame_horz = gtk_frame_new ("Member Of");
1233	gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1234
1235	vbox = gtk_vbox_new(FALSE, 0);
1236	gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1237	gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1238
1239	/* TWO ENTRIES */
1240	state->entry_workgroup = gtk_entry_new();
1241	state->entry_domain = gtk_entry_new();
1242
1243	/* DOMAIN */
1244	button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1245	if (state->name_type_initial == NetSetupDomainName) {
1246		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1247	}
1248	gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1249	g_signal_connect(G_OBJECT(button_domain), "clicked",
1250			 G_CALLBACK(callback_do_join_domain),
1251			 (gpointer)state);
1252
1253	{
1254		gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1255		g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1256				 G_CALLBACK(callback_enter_domain_and_unlock),
1257				 (gpointer)state);
1258		g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1259				 G_CALLBACK(callback_continue),
1260				 (gpointer)state);
1261		if (state->name_type_initial == NetSetupDomainName) {
1262			gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1263					   state->name_buffer_initial);
1264			gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1265			gtk_widget_set_sensitive(state->entry_domain, TRUE);
1266		}
1267		gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1268		gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1269		gtk_widget_show(state->entry_domain);
1270	}
1271	gtk_widget_show(button_domain);
1272
1273	/* WORKGROUP */
1274	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1275	button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1276	if (state->name_type_initial == NetSetupWorkgroupName) {
1277		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1278	}
1279	gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1280	g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1281			 G_CALLBACK(callback_do_join_workgroup),
1282			 (gpointer)state);
1283	{
1284		gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1285					 MAX_NETBIOS_NAME_LEN);
1286		g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1287				 G_CALLBACK(callback_enter_workgroup_and_unlock),
1288				 (gpointer)state);
1289		g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1290				 G_CALLBACK(callback_continue),
1291				 (gpointer)state);
1292
1293		if (state->name_type_initial == NetSetupWorkgroupName) {
1294			gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1295					   state->name_buffer_initial);
1296			gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1297			gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1298		}
1299		gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1300		gtk_widget_show(state->entry_workgroup);
1301	}
1302	gtk_widget_show(button_workgroup);
1303
1304	/* Advanced Options */
1305	frame_horz = gtk_frame_new("Advanced Options");
1306	gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1307
1308	vbox = gtk_vbox_new(FALSE, 0);
1309	gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1310	gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1311
1312	/* OUs */
1313	gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1314	gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1315	g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1316			 G_CALLBACK(callback_do_getous),
1317			 (gpointer)state);
1318
1319	state->entry_ou_list = gtk_combo_box_entry_new_text();
1320	gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1321	if (state->name_type_initial == NetSetupWorkgroupName) {
1322		gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1323		gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1324	}
1325	gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1326	gtk_widget_show(state->entry_ou_list);
1327
1328	{
1329		state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1330		gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1331		gtk_widget_set_sensitive(state->label_winbind, FALSE);
1332	}
1333
1334
1335	/* BUTTONS */
1336	bbox = gtk_hbutton_box_new();
1337	gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1338	gtk_container_add(GTK_CONTAINER(box1), bbox);
1339	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1340	gtk_box_set_spacing(GTK_BOX(bbox), 10);
1341
1342	state->window_do_change = window;
1343	gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1344	gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1345	g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1346			 G_CALLBACK(callback_do_join),
1347			 (gpointer)state);
1348
1349	button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1350	gtk_container_add(GTK_CONTAINER(bbox), button);
1351	g_signal_connect(G_OBJECT(button), "clicked",
1352			 G_CALLBACK(callback_do_freeauth_and_close),
1353			 (gpointer)state);
1354
1355	gtk_widget_show_all(window);
1356}
1357
1358static void callback_do_about(GtkWidget *widget,
1359			     gpointer data)
1360{
1361	GdkPixbuf *logo;
1362	GError    *error = NULL;
1363	GtkWidget *about;
1364
1365	struct join_state *state = (struct join_state *)data;
1366
1367	debug("callback_do_about called\n");
1368
1369	logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1370	                                &error);
1371	if (logo == NULL) {
1372		g_print("failed to load logo from %s: %s\n",
1373			SAMBA_IMAGE_PATH, error->message);
1374	}
1375
1376	about = gtk_about_dialog_new();
1377	gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1378	gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1379	gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1380		"Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1381		"Copyright Günther Deschner 2007-2008");
1382	gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1383	gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1384	gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1385	if (logo) {
1386		gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1387	}
1388	gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1389	gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1390	gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
1391	g_signal_connect_swapped(about, "response",
1392				 G_CALLBACK(gtk_widget_destroy),
1393				 about);
1394
1395	gtk_widget_show(about);
1396}
1397
1398static int draw_main_window(struct join_state *state)
1399{
1400	GtkWidget *window;
1401	GtkWidget *button;
1402	GtkWidget *label;
1403	GtkWidget *main_vbox;
1404	GtkWidget *vbox;
1405	GtkWidget *hbox;
1406	GtkWidget *bbox;
1407	GtkWidget *image;
1408	GtkWidget *table;
1409	GtkWidget *entry;
1410	GdkPixbuf *icon;
1411	GError    *error = NULL;
1412
1413	icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1414	                                &error);
1415	if (icon == NULL) {
1416		g_print("failed to load icon from %s : %s\n",
1417			SAMBA_ICON_PATH, error->message);
1418	}
1419
1420#if 1
1421	image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1422#else
1423	image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1424#endif
1425	if (image == NULL) {
1426		g_print("failed to load logo from %s : %s\n",
1427			SAMBA_IMAGE_PATH_SMALL, error->message);
1428	}
1429
1430	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1431	state->window_main = window;
1432
1433	gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1434	gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1435	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1436	gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1437	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1438
1439	g_signal_connect(G_OBJECT(window), "delete_event",
1440			 G_CALLBACK(callback_delete_event), NULL);
1441
1442	gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1443
1444	main_vbox = gtk_vbox_new(FALSE, 10);
1445	gtk_container_add(GTK_CONTAINER(window), main_vbox);
1446
1447#if 0
1448	gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1449	gtk_widget_show(image);
1450#endif
1451	/* Hbox */
1452	hbox = gtk_hbox_new(FALSE, 10);
1453	gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1454
1455	{
1456/*		gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1457/*		gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1458		gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1459		gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1460		gtk_widget_show(image);
1461
1462		/* Label */
1463		label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1464/*		gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1465		gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1466		gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1467		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1468		gtk_widget_show(label);
1469	}
1470
1471	gtk_widget_show(hbox);
1472
1473	vbox = gtk_vbox_new(FALSE, 0);
1474	gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1475	gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1476
1477	/* Table */
1478	table = gtk_table_new(6, 3, TRUE);
1479	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1480	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1481	gtk_container_add(GTK_CONTAINER(vbox), table);
1482
1483	{
1484		/* Label */
1485		label = gtk_label_new("Computer description:");
1486		gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1487		gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1488		gtk_widget_show(label);
1489
1490		state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1491
1492		/* Entry */
1493		entry = gtk_entry_new();
1494		gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1495
1496		if (!state->target_hostname && state->uid != 0) {
1497			gtk_widget_set_sensitive(GTK_WIDGET(entry), FALSE);
1498		}
1499		g_signal_connect(G_OBJECT(entry), "changed",
1500				 G_CALLBACK(callback_enter_computer_description_and_unlock),
1501				 state);
1502		g_signal_connect(G_OBJECT(entry), "activate",
1503				 G_CALLBACK(callback_apply_continue),
1504				 (gpointer)state);
1505
1506		gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1507		gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1508		gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1509		gtk_widget_show(entry);
1510	}
1511
1512	/* Label */
1513	label = gtk_label_new("For example: \"Samba \%v\".");
1514	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1515	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1516	gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1517	gtk_widget_show(label);
1518
1519	/* Label */
1520	label = gtk_label_new("Full computer name:");
1521	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1522	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1523	gtk_widget_show(label);
1524
1525	{
1526		/* Label */
1527		char *str = NULL;
1528		if (state->name_type_initial == NetSetupDomainName) {
1529			if (asprintf(&str, "%s.%s", state->my_hostname,
1530				 state->my_dnsdomain) == -1) {
1531				return -1;
1532			}
1533		} else {
1534			if (asprintf(&str, "%s.", state->my_hostname) == -1) {
1535				return -1;
1536			}
1537		}
1538
1539		label = gtk_label_new(str);
1540		SAFE_FREE(str);
1541		gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1542		gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1543		gtk_widget_show(label);
1544	}
1545
1546	/* Label */
1547	if (state->name_type_initial == NetSetupDomainName) {
1548		label = gtk_label_new("Domain:");
1549	} else {
1550		label = gtk_label_new("Workgroup:");
1551	}
1552	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1553	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1554	gtk_widget_show(label);
1555	state->label_current_name_type = label;
1556
1557	/* Label */
1558	label = gtk_label_new(state->name_buffer_initial);
1559	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1560	gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1561	gtk_widget_show(label);
1562	state->label_current_name_buffer = label;
1563
1564	{
1565		hbox = gtk_hbox_new(FALSE, 0);
1566		gtk_container_add(GTK_CONTAINER(vbox), hbox);
1567		label = gtk_label_new("To rename this computer or join a domain, click Change.");
1568		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1569
1570
1571	}
1572
1573	/* bbox */
1574	bbox = gtk_hbutton_box_new();
1575	gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1576	gtk_container_add(GTK_CONTAINER(hbox), bbox);
1577	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1578	gtk_box_set_spacing(GTK_BOX(bbox), 10);
1579
1580	button = gtk_button_new_with_mnemonic("Ch_ange");
1581	g_signal_connect(G_OBJECT(button), "clicked",
1582			 G_CALLBACK(callback_do_change),
1583			 (gpointer)state);
1584	gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1585	if (!state->target_hostname && state->uid != 0) {
1586		gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
1587	}
1588	gtk_widget_show(button);
1589
1590	/* Label (hidden) */
1591	state->label_reboot = gtk_label_new(NULL);
1592	gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1593	gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1594	gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1595	if (!state->target_hostname && state->uid != 0) {
1596		gtk_label_set_text(GTK_LABEL(state->label_reboot),
1597			   "You cannot change computer description as you're not running with root permissions");
1598	}
1599
1600	gtk_widget_show(state->label_reboot);
1601
1602#if 0
1603	gtk_box_pack_start(GTK_BOX(vbox),
1604	   create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1605		      TRUE, TRUE, 5);
1606#endif
1607	{
1608
1609		GtkWidget *frame;
1610		GtkWidget *bbox2;
1611		GtkWidget *button2;
1612
1613		frame = gtk_frame_new(NULL);
1614		bbox2 = gtk_hbutton_box_new();
1615
1616		gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1617		gtk_container_add(GTK_CONTAINER(frame), bbox2);
1618
1619		/* Set the appearance of the Button Box */
1620		gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1621		gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1622		/*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1623
1624		button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1625		gtk_container_add(GTK_CONTAINER(bbox2), button2);
1626		g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1627
1628		button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1629		gtk_container_add(GTK_CONTAINER(bbox2), button2);
1630		g_signal_connect(G_OBJECT(button2), "clicked",
1631				 G_CALLBACK(callback_delete_event),
1632				 window);
1633
1634		gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1635		g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1636				 G_CALLBACK(callback_apply_description_change),
1637				 state);
1638		gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1639
1640		button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1641		gtk_container_add(GTK_CONTAINER(bbox2), button2);
1642		g_signal_connect(G_OBJECT(button2), "clicked",
1643				 G_CALLBACK(callback_do_about),
1644				 state);
1645#if 0
1646		button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1647		gtk_container_add(GTK_CONTAINER(bbox2), button2);
1648		g_signal_connect(G_OBJECT(button2), "clicked",
1649				 G_CALLBACK(callback_do_about),
1650				 window);
1651#endif
1652		gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1653	}
1654
1655	gtk_widget_show_all(window);
1656
1657	return 0;
1658}
1659
1660static int init_join_state(struct join_state **state)
1661{
1662	struct join_state *s;
1663
1664	s = (struct join_state *)malloc(sizeof(struct join_state));
1665	if (!s) {
1666		return -1;
1667	}
1668
1669	memset(s, '\0', sizeof(struct join_state));
1670
1671	*state = s;
1672
1673	return 0;
1674}
1675
1676static NET_API_STATUS get_server_properties(struct join_state *state)
1677{
1678	struct SERVER_INFO_101 *info101 = NULL;
1679	struct SERVER_INFO_1005 *info1005 = NULL;
1680	NET_API_STATUS status;
1681
1682	status = NetServerGetInfo(state->target_hostname,
1683				  101,
1684				  (uint8_t **)&info101);
1685	if (status == 0) {
1686		state->comment = strdup(info101->sv101_comment);
1687		if (!state->comment) {
1688			return -1;
1689		}
1690		SAFE_FREE(state->my_hostname);
1691		state->my_hostname = strdup(info101->sv101_name);
1692		if (!state->my_hostname) {
1693			return -1;
1694		}
1695		NetApiBufferFree(info101);
1696		return NET_API_STATUS_SUCCESS;
1697	}
1698
1699	switch (status) {
1700		case 124: /* WERR_UNKNOWN_LEVEL */
1701		case 50: /* WERR_NOT_SUPPORTED */
1702			break;
1703		default:
1704			goto failed;
1705	}
1706
1707	status = NetServerGetInfo(state->target_hostname,
1708				  1005,
1709				  (uint8_t **)&info1005);
1710	if (status == 0) {
1711		state->comment = strdup(info1005->sv1005_comment);
1712		if (!state->comment) {
1713			return -1;
1714		}
1715		NetApiBufferFree(info1005);
1716		return NET_API_STATUS_SUCCESS;
1717	}
1718
1719 failed:
1720	printf("NetServerGetInfo failed with: %s\n",
1721		libnetapi_get_error_string(state->ctx, status));
1722
1723	return status;
1724}
1725
1726static int initialize_join_state(struct join_state *state,
1727				 const char *debug_level,
1728				 const char *target_hostname,
1729				 const char *target_username)
1730{
1731	struct libnetapi_ctx *ctx = NULL;
1732	NET_API_STATUS status = 0;
1733
1734	status = libnetapi_init(&ctx);
1735	if (status) {
1736		return status;
1737	}
1738
1739	if (debug_level) {
1740		libnetapi_set_debuglevel(ctx, debug_level);
1741	}
1742
1743	if (target_hostname) {
1744		state->target_hostname = strdup(target_hostname);
1745		if (!state->target_hostname) {
1746			return -1;
1747		}
1748	}
1749
1750	if (target_username) {
1751		char *puser = strdup(target_username);
1752		char *p = NULL;
1753
1754		if ((p = strchr(puser,'%'))) {
1755			size_t len;
1756			*p = 0;
1757			libnetapi_set_username(ctx, puser);
1758			libnetapi_set_password(ctx, p+1);
1759			len = strlen(p+1);
1760			memset(strchr(target_username,'%')+1,'X',len);
1761		} else {
1762			libnetapi_set_username(ctx, puser);
1763		}
1764		free(puser);
1765	}
1766
1767	{
1768		char my_hostname[HOST_NAME_MAX];
1769		const char *p = NULL;
1770		struct hostent *hp = NULL;
1771
1772		if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1773			return -1;
1774		}
1775
1776		p = strchr(my_hostname, '.');
1777		if (p) {
1778			my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1779		}
1780		state->my_hostname = strdup(my_hostname);
1781		if (!state->my_hostname) {
1782			return -1;
1783		}
1784		debug("state->my_hostname: %s\n", state->my_hostname);
1785
1786		hp = gethostbyname(my_hostname);
1787		if (!hp || !hp->h_name || !*hp->h_name) {
1788			return -1;
1789		}
1790
1791		state->my_fqdn = strdup(hp->h_name);
1792		if (!state->my_fqdn) {
1793			return -1;
1794		}
1795		debug("state->my_fqdn: %s\n", state->my_fqdn);
1796
1797		p = strchr(state->my_fqdn, '.');
1798		if (p) {
1799			p++;
1800			state->my_dnsdomain = strdup(p);
1801		} else {
1802			state->my_dnsdomain = strdup("");
1803		}
1804		if (!state->my_dnsdomain) {
1805			return -1;
1806		}
1807		debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1808	}
1809
1810	{
1811		const char *buffer = NULL;
1812		uint16_t type = 0;
1813		status = NetGetJoinInformation(state->target_hostname,
1814					       &buffer,
1815					       &type);
1816		if (status != 0) {
1817			printf("NetGetJoinInformation failed with: %s\n",
1818				libnetapi_get_error_string(state->ctx, status));
1819			return status;
1820		}
1821		debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1822		state->name_buffer_initial = strdup(buffer);
1823		if (!state->name_buffer_initial) {
1824			return -1;
1825		}
1826		state->name_type_initial = type;
1827		NetApiBufferFree((void *)buffer);
1828	}
1829
1830	status = get_server_properties(state);
1831	if (status != 0) {
1832		return -1;
1833	}
1834
1835	state->uid = geteuid();
1836
1837	state->ctx = ctx;
1838
1839	return 0;
1840}
1841
1842int main(int argc, char **argv)
1843{
1844	GOptionContext *context = NULL;
1845	static const char *debug_level = NULL;
1846	static const char *target_hostname = NULL;
1847	static const char *target_username = NULL;
1848	struct join_state *state = NULL;
1849	GError *error = NULL;
1850	int ret = 0;
1851
1852	static GOptionEntry entries[] = {
1853		{ "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1854		{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1855		{ "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
1856		{ "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
1857		{ NULL }
1858	};
1859
1860	context = g_option_context_new("- Samba domain join utility");
1861	g_option_context_add_main_entries(context, entries, NULL);
1862/*	g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1863	g_option_context_add_group(context, gtk_get_option_group(TRUE));
1864	g_option_context_parse(context, &argc, &argv, &error);
1865
1866	gtk_init(&argc, &argv);
1867	g_set_application_name("Samba");
1868
1869	ret = init_join_state(&state);
1870	if (ret) {
1871		return ret;
1872	}
1873
1874	ret = initialize_join_state(state, debug_level,
1875				    target_hostname,
1876				    target_username);
1877	if (ret) {
1878		return ret;
1879	}
1880
1881	draw_main_window(state);
1882
1883	gtk_main();
1884
1885	do_cleanup(state);
1886
1887	return 0;
1888}
1889