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