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