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