0a06a7789cb88f4d4caeb6fea849539e7de84233
[jra/samba/.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 callback_creds_prompt(GtkWidget *widget,
85                                   gpointer data,
86                                   const char *label_string,
87                                   gpointer cont_fn);
88
89
90 static 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
103 static gboolean callback_delete_event(GtkWidget *widget,
104                                       GdkEvent *event,
105                                       gpointer data)
106 {
107         gtk_main_quit();
108         return FALSE;
109 }
110
111 static 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
121 static 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
131 static 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
147 static 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
167 static 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
180 static void do_cleanup(struct join_state *state)
181 {
182         libnetapi_free(state->ctx);
183         free_join_state(state);
184 }
185
186 static 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
224 static 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
267 static 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
336 static 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
354 static 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
372 static 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
394 static 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
416 static 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
435 static 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
444 static 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
451 static 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
459 static 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                                         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
533 static 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
634 static 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
869 static 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
909 static 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
941 static 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                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
955                 return;
956         }
957         gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
958         SAFE_FREE(state->name_buffer_new);
959         state->name_buffer_new = strdup(entry_text);
960         state->name_type_new = NetSetupWorkgroupName;
961 }
962
963 static void callback_enter_domain_and_unlock(GtkWidget *widget,
964                                              gpointer data)
965 {
966         const gchar *entry_text = NULL;
967         struct join_state *state = (struct join_state *)data;
968
969         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
970         debug("callback_enter_domain_and_unlock: %s\n", entry_text);
971         if (!entry_text || entry_text[0] == 0) {
972                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
973                 return;
974         }
975         if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
976                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
977                 return;
978         }
979         gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
980         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), TRUE);
981         gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), TRUE);
982         SAFE_FREE(state->name_buffer_new);
983         state->name_buffer_new = strdup(entry_text);
984         state->name_type_new = NetSetupDomainName;
985 }
986
987 static void callback_apply_continue(GtkWidget *widget,
988                                     gpointer data)
989 {
990         struct join_state *state = (struct join_state *)data;
991
992         gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
993         g_signal_emit_by_name(state->button_apply, "clicked");
994 }
995
996 static void callback_do_join_workgroup(GtkWidget *widget,
997                                        gpointer data)
998 {
999         struct join_state *state = (struct join_state *)data;
1000         debug("callback_do_join_workgroup choosen\n");
1001         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1002         gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
1003         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1004         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_ou_list), FALSE);
1005         gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1006         callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
1007 }
1008
1009 static void callback_do_join_domain(GtkWidget *widget,
1010                                     gpointer data)
1011 {
1012         struct join_state *state = (struct join_state *)data;
1013         debug("callback_do_join_domain choosen\n");
1014         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
1015         gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
1016         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
1017         callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
1018 }
1019
1020 static void callback_do_getous(GtkWidget *widget,
1021                                gpointer data)
1022 {
1023         NET_API_STATUS status;
1024         uint32_t num_ous = 0;
1025         const char **ous = NULL;
1026         int i;
1027         const char *domain = NULL;
1028         struct DOMAIN_CONTROLLER_INFO *dc_info = NULL;
1029         const char *err_str = NULL;
1030         GtkWidget *dialog;
1031
1032         struct join_state *state = (struct join_state *)data;
1033
1034         debug("callback_do_getous called\n");
1035
1036         domain = state->name_buffer_new ? state->name_buffer_new : state->name_buffer_initial;
1037
1038         status = DsGetDcName(NULL,
1039                              domain,
1040                              NULL,
1041                              NULL,
1042                              0,
1043                              &dc_info);
1044         if (status != 0) {
1045                 err_str = libnetapi_get_error_string(state->ctx, status);
1046                 g_print("callback_do_getous: failed find dc (%s)\n", err_str);
1047
1048                 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
1049                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
1050                                                 GTK_MESSAGE_ERROR,
1051                                                 GTK_BUTTONS_CLOSE,
1052                                                 "Failed to find a domain controller for domain: \"%s\": %s",
1053                                                 domain,
1054                                                 err_str);
1055
1056                 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1057                 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1058                 g_signal_connect_swapped(dialog, "response",
1059                                          G_CALLBACK(gtk_widget_destroy),
1060                                          dialog);
1061
1062                 gtk_widget_show(dialog);
1063
1064                 return;
1065         }
1066
1067         if (!state->account || !state->password) {
1068                 debug("callback_do_getous: no creds yet\n");
1069                 callback_creds_prompt(NULL, state,
1070                                       "Enter the name and password of an account with permission to join the domain.",
1071                                       callback_do_storeauth_and_scan);
1072         }
1073
1074         if (!state->account || !state->password) {
1075                 debug("callback_do_getous: still no creds ???\n");
1076                 return;
1077         }
1078
1079         status = NetGetJoinableOUs(state->target_hostname,
1080                                    domain,
1081                                    state->account,
1082                                    state->password,
1083                                    &num_ous, &ous);
1084         if (status != NET_API_STATUS_SUCCESS) {
1085                 callback_do_freeauth(NULL, state);
1086                 debug("failed to call NetGetJoinableOUs: %s\n",
1087                         libnetapi_get_error_string(state->ctx, status));
1088                 dialog = gtk_message_dialog_new(NULL,
1089                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
1090                                                 GTK_MESSAGE_INFO,
1091                                                 GTK_BUTTONS_OK,
1092                                                 "Failed to query joinable OUs: %s",
1093                                                 libnetapi_get_error_string(state->ctx, status));
1094                 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1095                 gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(state->window_do_change));
1096                 gtk_dialog_run(GTK_DIALOG(dialog));
1097                 gtk_widget_destroy(dialog);
1098                 return;
1099         }
1100
1101         for (i=0; i<state->stored_num_ous; i++) {
1102                 gtk_combo_box_remove_text(GTK_COMBO_BOX(state->entry_ou_list), 0);
1103         }
1104         for (i=0; i<num_ous && ous[i] != NULL; i++) {
1105                 gtk_combo_box_append_text(GTK_COMBO_BOX(state->entry_ou_list),
1106                                           ous[i]);
1107         }
1108         NetApiBufferFree(ous);
1109         state->stored_num_ous = num_ous;
1110         gtk_combo_box_set_active(GTK_COMBO_BOX(state->entry_ou_list), num_ous-1);
1111 }
1112
1113 static void callback_do_change(GtkWidget *widget,
1114                                gpointer data)
1115 {
1116         GtkWidget *window;
1117         GtkWidget *box1;
1118         GtkWidget *bbox;
1119         GtkWidget *button_workgroup;
1120         GtkWidget *button_domain;
1121         GtkWidget *button;
1122         GtkWidget *label;
1123         GtkWidget *frame_horz;
1124         GtkWidget *vbox;
1125         GtkWidget *entry;
1126         GSList *group;
1127
1128         struct join_state *state = (struct join_state *)data;
1129
1130         debug("callback_do_change called\n");
1131
1132 #if 0
1133         /* FIXME: add proper warnings for Samba as a DC */
1134         if (state->server_role == 3) {
1135                 GtkWidget *dialog;
1136                 callback_do_freeauth(NULL, state);
1137                 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
1138                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
1139                                                 GTK_MESSAGE_ERROR,
1140                                                 GTK_BUTTONS_OK,
1141                                                 "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.");
1142                 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1143                 g_signal_connect_swapped(dialog, "response",
1144                                          G_CALLBACK(gtk_widget_destroy),
1145                                          dialog);
1146
1147                 gtk_widget_show(dialog);
1148                 return;
1149         }
1150 #endif
1151
1152         state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
1153         state->button_get_ous = gtk_button_new_with_label("Scan for joinable OUs");
1154         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1155         gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1156
1157         gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
1158         gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1159         gtk_widget_set_size_request(GTK_WIDGET(window), 480, 650);
1160         gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1161         gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(state->window_main));
1162         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1163
1164         g_signal_connect(G_OBJECT(window), "delete_event",
1165                          G_CALLBACK(callback_do_close_widget), NULL);
1166
1167         gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1168
1169         box1 = gtk_vbox_new(FALSE, 0);
1170         gtk_container_add(GTK_CONTAINER(window), box1);
1171
1172         label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
1173         gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1174         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1175         gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1176         gtk_widget_show(label);
1177
1178         /* COMPUTER NAME */
1179         label = gtk_label_new("Computer name:");
1180         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1181         gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1182         gtk_widget_show(label);
1183
1184         state->label_full_computer_name = gtk_label_new(NULL);
1185         {
1186                 entry = gtk_entry_new();
1187                 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
1188                 g_signal_connect(G_OBJECT(entry), "changed",
1189                                  G_CALLBACK(callback_enter_hostname_and_unlock),
1190                                  (gpointer)state);
1191                 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
1192                 gtk_editable_select_region(GTK_EDITABLE(entry),
1193                                            0, GTK_ENTRY(entry)->text_length);
1194
1195                 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1196                 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
1197                 gtk_widget_show(entry);
1198         }
1199
1200         /* FULL COMPUTER NAME */
1201         label = gtk_label_new("Full computer name:");
1202         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1203         gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
1204         gtk_widget_show(label);
1205
1206         {
1207                 const gchar *entry_text;
1208                 char *str = NULL;
1209                 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1210                 if (state->name_type_initial == NetSetupDomainName) {
1211                         if (asprintf(&str, "%s.%s", entry_text,
1212                                  state->my_dnsdomain) == -1) {
1213                                 return;
1214                         }
1215                 } else {
1216                         if (asprintf(&str, "%s.", entry_text) == -1) {
1217                                 return;
1218                         }
1219                 }
1220                 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name),
1221                                    str);
1222                 free(str);
1223                 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
1224                 gtk_box_pack_start(GTK_BOX(box1),
1225                                    state->label_full_computer_name, TRUE, TRUE, 0);
1226                 gtk_widget_show(state->label_full_computer_name);
1227         }
1228
1229         /* BOX */
1230         frame_horz = gtk_frame_new ("Member Of");
1231         gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1232
1233         vbox = gtk_vbox_new(FALSE, 0);
1234         gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1235         gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1236
1237         /* TWO ENTRIES */
1238         state->entry_workgroup = gtk_entry_new();
1239         state->entry_domain = gtk_entry_new();
1240
1241         /* DOMAIN */
1242         button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
1243         if (state->name_type_initial == NetSetupDomainName) {
1244                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
1245         }
1246         gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
1247         g_signal_connect(G_OBJECT(button_domain), "clicked",
1248                          G_CALLBACK(callback_do_join_domain),
1249                          (gpointer)state);
1250
1251         {
1252                 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
1253                 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
1254                                  G_CALLBACK(callback_enter_domain_and_unlock),
1255                                  (gpointer)state);
1256                 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
1257                                  G_CALLBACK(callback_continue),
1258                                  (gpointer)state);
1259                 if (state->name_type_initial == NetSetupDomainName) {
1260                         gtk_entry_set_text(GTK_ENTRY(state->entry_domain),
1261                                            state->name_buffer_initial);
1262                         gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
1263                         gtk_widget_set_sensitive(state->entry_domain, TRUE);
1264                 }
1265                 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
1266                 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
1267                 gtk_widget_show(state->entry_domain);
1268         }
1269         gtk_widget_show(button_domain);
1270
1271         /* WORKGROUP */
1272         group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
1273         button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
1274         if (state->name_type_initial == NetSetupWorkgroupName) {
1275                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
1276         }
1277         gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
1278         g_signal_connect(G_OBJECT(button_workgroup), "clicked",
1279                          G_CALLBACK(callback_do_join_workgroup),
1280                          (gpointer)state);
1281         {
1282                 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup),
1283                                          MAX_NETBIOS_NAME_LEN);
1284                 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
1285                                  G_CALLBACK(callback_enter_workgroup_and_unlock),
1286                                  (gpointer)state);
1287                 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
1288                                  G_CALLBACK(callback_continue),
1289                                  (gpointer)state);
1290
1291                 if (state->name_type_initial == NetSetupWorkgroupName) {
1292                         gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup),
1293                                            state->name_buffer_initial);
1294                         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
1295                         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
1296                 }
1297                 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
1298                 gtk_widget_show(state->entry_workgroup);
1299         }
1300         gtk_widget_show(button_workgroup);
1301
1302         /* Advanced Options */
1303         frame_horz = gtk_frame_new("Advanced Options");
1304         gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
1305
1306         vbox = gtk_vbox_new(FALSE, 0);
1307         gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1308         gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
1309
1310         /* OUs */
1311         gtk_container_add(GTK_CONTAINER(vbox), state->button_get_ous);
1312         gtk_widget_set_sensitive(GTK_WIDGET(state->button_get_ous), FALSE);
1313         g_signal_connect(G_OBJECT(state->button_get_ous), "clicked",
1314                          G_CALLBACK(callback_do_getous),
1315                          (gpointer)state);
1316
1317         state->entry_ou_list = gtk_combo_box_entry_new_text();
1318         gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1319         if (state->name_type_initial == NetSetupWorkgroupName) {
1320                 gtk_widget_set_sensitive(state->entry_ou_list, FALSE);
1321                 gtk_widget_set_sensitive(state->button_get_ous, FALSE);
1322         }
1323         gtk_box_pack_start(GTK_BOX(vbox), state->entry_ou_list, TRUE, TRUE, 0);
1324         gtk_widget_show(state->entry_ou_list);
1325
1326         {
1327                 state->label_winbind = gtk_check_button_new_with_label("Modify winbind configuration");
1328                 gtk_box_pack_start(GTK_BOX(vbox), state->label_winbind, TRUE, TRUE, 0);
1329                 gtk_widget_set_sensitive(state->label_winbind, FALSE);
1330         }
1331
1332
1333         /* BUTTONS */
1334         bbox = gtk_hbutton_box_new();
1335         gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1336         gtk_container_add(GTK_CONTAINER(box1), bbox);
1337         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1338         gtk_box_set_spacing(GTK_BOX(bbox), 10);
1339
1340         state->window_do_change = window;
1341         gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
1342         gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
1343         g_signal_connect(G_OBJECT(state->button_ok), "clicked",
1344                          G_CALLBACK(callback_do_join),
1345                          (gpointer)state);
1346
1347         button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1348         gtk_container_add(GTK_CONTAINER(bbox), button);
1349         g_signal_connect(G_OBJECT(button), "clicked",
1350                          G_CALLBACK(callback_do_freeauth_and_close),
1351                          (gpointer)state);
1352
1353         gtk_widget_show_all(window);
1354 }
1355
1356 static void callback_do_about(GtkWidget *widget,
1357                              gpointer data)
1358 {
1359         GdkPixbuf *logo;
1360         GError    *error = NULL;
1361         GtkWidget *about;
1362
1363         struct join_state *state = (struct join_state *)data;
1364
1365         debug("callback_do_about called\n");
1366
1367         logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
1368                                         &error);
1369         if (logo == NULL) {
1370                 g_print("failed to load logo from %s: %s\n",
1371                         SAMBA_IMAGE_PATH, error->message);
1372         }
1373
1374         about = gtk_about_dialog_new();
1375         gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Samba");
1376         gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), "3.2.0pre3");
1377         gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
1378                 "Copyright Andrew Tridgell and the Samba Team 1992-2008\n"
1379                 "Copyright Günther Deschner 2007-2008");
1380         gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "GPLv3");
1381         gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1382         gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about), "http://www.samba.org");
1383         if (logo) {
1384                 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
1385         }
1386         gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), "Samba gtk domain join utility");
1387         gtk_window_set_modal(GTK_WINDOW(about), TRUE);
1388         gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(state->window_main));
1389         g_signal_connect_swapped(about, "response",
1390                                  G_CALLBACK(gtk_widget_destroy),
1391                                  about);
1392
1393         gtk_widget_show(about);
1394 }
1395
1396 static int draw_main_window(struct join_state *state)
1397 {
1398         GtkWidget *window;
1399         GtkWidget *button;
1400         GtkWidget *label;
1401         GtkWidget *main_vbox;
1402         GtkWidget *vbox;
1403         GtkWidget *hbox;
1404         GtkWidget *bbox;
1405         GtkWidget *image;
1406         GtkWidget *table;
1407         GtkWidget *entry;
1408         GdkPixbuf *icon;
1409         GError    *error = NULL;
1410
1411         icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
1412                                         &error);
1413         if (icon == NULL) {
1414                 g_print("failed to load icon from %s : %s\n",
1415                         SAMBA_ICON_PATH, error->message);
1416         }
1417
1418 #if 1
1419         image = gtk_image_new_from_file(SAMBA_IMAGE_PATH_SMALL);
1420 #else
1421         image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
1422 #endif
1423         if (image == NULL) {
1424                 g_print("failed to load logo from %s : %s\n",
1425                         SAMBA_IMAGE_PATH_SMALL, error->message);
1426         }
1427
1428         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1429         state->window_main = window;
1430
1431         gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
1432         gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600);
1433         gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
1434         gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
1435         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
1436
1437         g_signal_connect(G_OBJECT(window), "delete_event",
1438                          G_CALLBACK(callback_delete_event), NULL);
1439
1440         gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1441
1442         main_vbox = gtk_vbox_new(FALSE, 10);
1443         gtk_container_add(GTK_CONTAINER(window), main_vbox);
1444
1445 #if 0
1446         gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1447         gtk_widget_show(image);
1448 #endif
1449         /* Hbox */
1450         hbox = gtk_hbox_new(FALSE, 10);
1451         gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1452
1453         {
1454 /*              gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1455 /*              gtk_misc_set_alignment(GTK_MISC(image), 0, 0); */
1456                 gtk_widget_set_size_request(GTK_WIDGET(image), 150, 40);
1457                 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1458                 gtk_widget_show(image);
1459
1460                 /* Label */
1461                 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1462 /*              gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1463                 gtk_widget_set_size_request(GTK_WIDGET(label), 400, 40);
1464                 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1465                 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1466                 gtk_widget_show(label);
1467         }
1468
1469         gtk_widget_show(hbox);
1470
1471         vbox = gtk_vbox_new(FALSE, 0);
1472         gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1473         gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1474
1475         /* Table */
1476         table = gtk_table_new(6, 3, TRUE);
1477         gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1478         gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1479         gtk_container_add(GTK_CONTAINER(vbox), table);
1480
1481         {
1482                 /* Label */
1483                 label = gtk_label_new("Computer description:");
1484                 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1485                 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1486                 gtk_widget_show(label);
1487
1488                 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1489
1490                 /* Entry */
1491                 entry = gtk_entry_new();
1492                 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1493
1494                 if (!state->target_hostname && state->uid != 0) {
1495                         gtk_widget_set_sensitive(GTK_WIDGET(entry), FALSE);
1496                 }
1497                 g_signal_connect(G_OBJECT(entry), "changed",
1498                                  G_CALLBACK(callback_enter_computer_description_and_unlock),
1499                                  state);
1500                 g_signal_connect(G_OBJECT(entry), "activate",
1501                                  G_CALLBACK(callback_apply_continue),
1502                                  (gpointer)state);
1503
1504                 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1505                 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1506                 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1507                 gtk_widget_show(entry);
1508         }
1509
1510         /* Label */
1511         label = gtk_label_new("For example: \"Samba \%v\".");
1512         gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1513         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1514         gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1515         gtk_widget_show(label);
1516
1517         /* Label */
1518         label = gtk_label_new("Full computer name:");
1519         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1520         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1521         gtk_widget_show(label);
1522
1523         {
1524                 /* Label */
1525                 char *str = NULL;
1526                 if (state->name_type_initial == NetSetupDomainName) {
1527                         if (asprintf(&str, "%s.%s", state->my_hostname,
1528                                  state->my_dnsdomain) == -1) {
1529                                 return -1;
1530                         }
1531                 } else {
1532                         if (asprintf(&str, "%s.", state->my_hostname) == -1) {
1533                                 return -1;
1534                         }
1535                 }
1536
1537                 label = gtk_label_new(str);
1538                 SAFE_FREE(str);
1539                 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1540                 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1541                 gtk_widget_show(label);
1542         }
1543
1544         /* Label */
1545         if (state->name_type_initial == NetSetupDomainName) {
1546                 label = gtk_label_new("Domain:");
1547         } else {
1548                 label = gtk_label_new("Workgroup:");
1549         }
1550         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1551         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1552         gtk_widget_show(label);
1553         state->label_current_name_type = label;
1554
1555         /* Label */
1556         label = gtk_label_new(state->name_buffer_initial);
1557         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1558         gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1559         gtk_widget_show(label);
1560         state->label_current_name_buffer = label;
1561
1562         {
1563                 hbox = gtk_hbox_new(FALSE, 0);
1564                 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1565                 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1566                 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1567
1568
1569         }
1570
1571         /* bbox */
1572         bbox = gtk_hbutton_box_new();
1573         gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1574         gtk_container_add(GTK_CONTAINER(hbox), bbox);
1575         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1576         gtk_box_set_spacing(GTK_BOX(bbox), 10);
1577
1578         button = gtk_button_new_with_mnemonic("Ch_ange");
1579         g_signal_connect(G_OBJECT(button), "clicked",
1580                          G_CALLBACK(callback_do_change),
1581                          (gpointer)state);
1582         gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1583         if (!state->target_hostname && state->uid != 0) {
1584                 gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
1585         }
1586         gtk_widget_show(button);
1587
1588         /* Label (hidden) */
1589         state->label_reboot = gtk_label_new(NULL);
1590         gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1591         gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1592         gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1593         if (!state->target_hostname && state->uid != 0) {
1594                 gtk_label_set_text(GTK_LABEL(state->label_reboot),
1595                            "You cannot change computer description as you're not running with root permissions");
1596         }
1597
1598         gtk_widget_show(state->label_reboot);
1599
1600 #if 0
1601         gtk_box_pack_start(GTK_BOX(vbox),
1602            create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1603                       TRUE, TRUE, 5);
1604 #endif
1605         {
1606
1607                 GtkWidget *frame;
1608                 GtkWidget *bbox2;
1609                 GtkWidget *button2;
1610
1611                 frame = gtk_frame_new(NULL);
1612                 bbox2 = gtk_hbutton_box_new();
1613
1614                 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1615                 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1616
1617                 /* Set the appearance of the Button Box */
1618                 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1619                 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1620                 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1621
1622                 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1623                 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1624                 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1625
1626                 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1627                 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1628                 g_signal_connect(G_OBJECT(button2), "clicked",
1629                                  G_CALLBACK(callback_delete_event),
1630                                  window);
1631
1632                 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1633                 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1634                                  G_CALLBACK(callback_apply_description_change),
1635                                  state);
1636                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1637
1638                 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1639                 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1640                 g_signal_connect(G_OBJECT(button2), "clicked",
1641                                  G_CALLBACK(callback_do_about),
1642                                  state);
1643 #if 0
1644                 button2 = gtk_button_new_from_stock(GTK_STOCK_HELP);
1645                 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1646                 g_signal_connect(G_OBJECT(button2), "clicked",
1647                                  G_CALLBACK(callback_do_about),
1648                                  window);
1649 #endif
1650                 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1651         }
1652
1653         gtk_widget_show_all(window);
1654
1655         return 0;
1656 }
1657
1658 static int init_join_state(struct join_state **state)
1659 {
1660         struct join_state *s;
1661
1662         s = (struct join_state *)malloc(sizeof(struct join_state));
1663         if (!s) {
1664                 return -1;
1665         }
1666
1667         memset(s, '\0', sizeof(struct join_state));
1668
1669         *state = s;
1670
1671         return 0;
1672 }
1673
1674 static NET_API_STATUS get_server_properties(struct join_state *state)
1675 {
1676         struct SERVER_INFO_101 *info101 = NULL;
1677         struct SERVER_INFO_1005 *info1005 = NULL;
1678         NET_API_STATUS status;
1679
1680         status = NetServerGetInfo(state->target_hostname,
1681                                   101,
1682                                   (uint8_t **)&info101);
1683         if (status == 0) {
1684                 state->comment = strdup(info101->sv101_comment);
1685                 if (!state->comment) {
1686                         return -1;
1687                 }
1688                 SAFE_FREE(state->my_hostname);
1689                 state->my_hostname = strdup(info101->sv101_name);
1690                 if (!state->my_hostname) {
1691                         return -1;
1692                 }
1693                 NetApiBufferFree(info101);
1694                 return NET_API_STATUS_SUCCESS;
1695         }
1696
1697         switch (status) {
1698                 case 124: /* WERR_UNKNOWN_LEVEL */
1699                 case 50: /* WERR_NOT_SUPPORTED */
1700                         break;
1701                 default:
1702                         goto failed;
1703         }
1704
1705         status = NetServerGetInfo(state->target_hostname,
1706                                   1005,
1707                                   (uint8_t **)&info1005);
1708         if (status == 0) {
1709                 state->comment = strdup(info1005->sv1005_comment);
1710                 if (!state->comment) {
1711                         return -1;
1712                 }
1713                 NetApiBufferFree(info1005);
1714                 return NET_API_STATUS_SUCCESS;
1715         }
1716
1717  failed:
1718         printf("NetServerGetInfo failed with: %s\n",
1719                 libnetapi_get_error_string(state->ctx, status));
1720
1721         return status;
1722 }
1723
1724 static int initialize_join_state(struct join_state *state,
1725                                  const char *debug_level,
1726                                  const char *target_hostname,
1727                                  const char *target_username)
1728 {
1729         struct libnetapi_ctx *ctx = NULL;
1730         NET_API_STATUS status = 0;
1731
1732         status = libnetapi_init(&ctx);
1733         if (status) {
1734                 return status;
1735         }
1736
1737         if (debug_level) {
1738                 libnetapi_set_debuglevel(ctx, debug_level);
1739         }
1740
1741         if (target_hostname) {
1742                 state->target_hostname = strdup(target_hostname);
1743                 if (!state->target_hostname) {
1744                         return -1;
1745                 }
1746         }
1747
1748         if (target_username) {
1749                 char *puser = strdup(target_username);
1750                 char *p = NULL;
1751
1752                 if ((p = strchr(puser,'%'))) {
1753                         size_t len;
1754                         *p = 0;
1755                         libnetapi_set_username(ctx, puser);
1756                         libnetapi_set_password(ctx, p+1);
1757                         len = strlen(p+1);
1758                         memset(strchr(target_username,'%')+1,'X',len);
1759                 } else {
1760                         libnetapi_set_username(ctx, puser);
1761                 }
1762                 free(puser);
1763         }
1764
1765         {
1766                 char my_hostname[HOST_NAME_MAX];
1767                 const char *p = NULL;
1768                 struct hostent *hp = NULL;
1769
1770                 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1771                         return -1;
1772                 }
1773
1774                 p = strchr(my_hostname, '.');
1775                 if (p) {
1776                         my_hostname[strlen(my_hostname)-strlen(p)] = '\0';
1777                 }
1778                 state->my_hostname = strdup(my_hostname);
1779                 if (!state->my_hostname) {
1780                         return -1;
1781                 }
1782                 debug("state->my_hostname: %s\n", state->my_hostname);
1783
1784                 hp = gethostbyname(my_hostname);
1785                 if (!hp || !hp->h_name || !*hp->h_name) {
1786                         return -1;
1787                 }
1788
1789                 state->my_fqdn = strdup(hp->h_name);
1790                 if (!state->my_fqdn) {
1791                         return -1;
1792                 }
1793                 debug("state->my_fqdn: %s\n", state->my_fqdn);
1794
1795                 p = strchr(state->my_fqdn, '.');
1796                 if (p) {
1797                         p++;
1798                         state->my_dnsdomain = strdup(p);
1799                 } else {
1800                         state->my_dnsdomain = strdup("");
1801                 }
1802                 if (!state->my_dnsdomain) {
1803                         return -1;
1804                 }
1805                 debug("state->my_dnsdomain: %s\n", state->my_dnsdomain);
1806         }
1807
1808         {
1809                 const char *buffer = NULL;
1810                 uint16_t type = 0;
1811                 status = NetGetJoinInformation(state->target_hostname,
1812                                                &buffer,
1813                                                &type);
1814                 if (status != 0) {
1815                         printf("NetGetJoinInformation failed with: %s\n",
1816                                 libnetapi_get_error_string(state->ctx, status));
1817                         return status;
1818                 }
1819                 debug("NetGetJoinInformation gave: %s and %d\n", buffer, type);
1820                 state->name_buffer_initial = strdup(buffer);
1821                 if (!state->name_buffer_initial) {
1822                         return -1;
1823                 }
1824                 state->name_type_initial = type;
1825                 NetApiBufferFree((void *)buffer);
1826         }
1827
1828         status = get_server_properties(state);
1829         if (status != 0) {
1830                 return -1;
1831         }
1832
1833         state->uid = geteuid();
1834
1835         state->ctx = ctx;
1836
1837         return 0;
1838 }
1839
1840 int main(int argc, char **argv)
1841 {
1842         GOptionContext *context = NULL;
1843         static const char *debug_level = NULL;
1844         static const char *target_hostname = NULL;
1845         static const char *target_username = NULL;
1846         struct join_state *state = NULL;
1847         GError *error = NULL;
1848         int ret = 0;
1849
1850         static GOptionEntry entries[] = {
1851                 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1852                 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1853                 { "target", 'S', 0, G_OPTION_ARG_STRING, &target_hostname, "Target hostname", 0 },
1854                 { "username", 'U', 0, G_OPTION_ARG_STRING, &target_username, "Target hostname", 0 },
1855                 { NULL }
1856         };
1857
1858         context = g_option_context_new("- Samba domain join utility");
1859         g_option_context_add_main_entries(context, entries, NULL);
1860 /*      g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1861         g_option_context_add_group(context, gtk_get_option_group(TRUE));
1862         g_option_context_parse(context, &argc, &argv, &error);
1863
1864         gtk_init(&argc, &argv);
1865         g_set_application_name("Samba");
1866
1867         ret = init_join_state(&state);
1868         if (ret) {
1869                 return ret;
1870         }
1871
1872         ret = initialize_join_state(state, debug_level,
1873                                     target_hostname,
1874                                     target_username);
1875         if (ret) {
1876                 return ret;
1877         }
1878
1879         draw_main_window(state);
1880
1881         gtk_main();
1882
1883         do_cleanup(state);
1884
1885         return 0;
1886 }