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