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