We may use 127k read/write for encrypted connections.
[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
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
28 #include <gtk/gtk.h>
29 #include <glib/gprintf.h>
30
31 #include <netapi.h>
32
33 #define MAX_CRED_LEN 256
34 #define MAX_NETBIOS_NAME_LEN 15
35
36 #define SAMBA_ICON_PATH  "/usr/share/pixmaps/samba/samba.ico"
37 #define SAMBA_IMAGE_PATH "/usr/share/pixmaps/samba/logo.png"
38
39 #define WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED ( 0x00000020 )
40 #define WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE ( 0x00000004 )
41 #define WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE ( 0x00000002 )
42 #define WKSSVC_JOIN_FLAGS_JOIN_TYPE ( 0x00000001 )
43
44 #define NetSetupWorkgroupName ( 2 )
45 #define NetSetupDomainName ( 3 )
46
47 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
48
49 struct srvsvc_NetSrvInfo1005 {
50         const char *comment;/* [unique,charset(UTF16)] */
51 };
52
53 static gboolean verbose = FALSE;
54
55 typedef struct join_state {
56         struct libnetapi_ctx *ctx;
57         GtkWidget *window_main;
58         GtkWidget *window_parent;
59         GtkWidget *window_do_change;
60         GtkWidget *window_creds_prompt;
61         GtkWidget *entry_account;
62         GtkWidget *entry_password;
63         GtkWidget *entry_domain;
64         GtkWidget *entry_workgroup;
65         GtkWidget *button_ok;
66         GtkWidget *button_apply;
67         GtkWidget *button_ok_creds;
68         GtkWidget *label_reboot;
69         GtkWidget *label_current_name_buffer;
70         GtkWidget *label_current_name_type;
71         GtkWidget *label_full_computer_name;
72         uint16_t name_type_initial;
73         uint16_t name_type_new;
74         char *name_buffer_initial;
75         char *name_buffer_new;
76         char *password;
77         char *account;
78         char *comment;
79         char *comment_new;
80         char *my_fqdn;
81         char *my_dnsdomain;
82         char *my_hostname;
83         uint16_t server_role;
84         gboolean settings_changed;
85         gboolean hostname_changed;
86 } join_state;
87
88 static void debug(const char *format, ...)
89 {
90         va_list args;
91
92         if (!verbose) {
93                 return;
94         }
95
96         va_start(args, format);
97         g_vprintf(format, args);
98         va_end(args);
99 }
100
101 static gboolean callback_delete_event(GtkWidget *widget,
102                                       GdkEvent *event,
103                                       gpointer data)
104 {
105         gtk_main_quit();
106         return FALSE;
107 }
108
109 static void callback_do_close(GtkWidget *widget,
110                               gpointer data)
111 {
112         debug("Closing now...\n");
113         gtk_widget_destroy(data);
114 }
115
116 static void free_join_state(struct join_state *s)
117 {
118         SAFE_FREE(s->name_buffer_initial);
119         SAFE_FREE(s->name_buffer_new);
120         SAFE_FREE(s->password);
121         SAFE_FREE(s->account);
122         SAFE_FREE(s->comment);
123         SAFE_FREE(s->comment_new);
124         SAFE_FREE(s->my_fqdn);
125         SAFE_FREE(s->my_dnsdomain);
126         SAFE_FREE(s->my_hostname);
127
128 }
129
130 static void do_cleanup(struct join_state *state)
131 {
132         libnetapi_free(state->ctx);
133         free_join_state(state);
134 }
135
136 static void callback_apply_description_change(GtkWidget *widget,
137                                               gpointer data)
138 {
139         struct join_state *state = (struct join_state *)data;
140         NET_API_STATUS status = 0;
141         uint32_t parm_err = 0;
142         struct srvsvc_NetSrvInfo1005 info1005;
143         GtkWidget *dialog;
144
145         info1005.comment = state->comment_new;
146
147         status = NetServerSetInfo(NULL, 1005, (uint8_t *)&info1005, &parm_err); 
148         if (status) {
149                 debug("NetServerSetInfo failed with: %s\n",
150                         libnetapi_errstr(state->ctx, status));
151                 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
152                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
153                                                 GTK_MESSAGE_ERROR,
154                                                 GTK_BUTTONS_OK,
155                                                 "Failed to change computer description: %s.",
156                                                 libnetapi_errstr(state->ctx, status));
157                 g_signal_connect_swapped(dialog, "response",
158                                          G_CALLBACK(gtk_widget_destroy),
159                                          dialog);
160
161                 gtk_widget_show(dialog);
162                 return;
163         }
164
165         gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
166 }
167
168 static void callback_do_exit(GtkWidget *widget,
169                              gpointer data)
170 {
171         GtkWidget *dialog;
172         gint result;
173         struct join_state *state = (struct join_state *)data;
174
175         if (!state->settings_changed) {
176                 callback_delete_event(NULL, NULL, NULL);
177                 return;
178         }
179
180         dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
181                                         GTK_DIALOG_DESTROY_WITH_PARENT,
182                                         GTK_MESSAGE_QUESTION,
183                                         GTK_BUTTONS_YES_NO,
184                                         "You must restart your computer before the new settings will take effect.");
185         result = gtk_dialog_run(GTK_DIALOG(dialog));
186         switch (result) {
187                 case GTK_RESPONSE_YES:
188                         g_print("would reboot here\n");
189                         break;
190                 case GTK_RESPONSE_NO:
191                 default:
192                         break;
193         }
194         gtk_widget_destroy(dialog);
195         gtk_widget_destroy(state->window_main);
196         do_cleanup(state);
197         exit(0);
198 }
199
200
201 static void callback_do_reboot(GtkWidget *widget,
202                                gpointer data,
203                                gpointer data2)
204 {
205         GtkWidget *dialog;
206         struct join_state *state = (struct join_state *)data2;
207
208         debug("callback_do_reboot\n");
209
210         state->settings_changed = TRUE;
211         dialog = gtk_message_dialog_new(GTK_WINDOW(data),
212                                         GTK_DIALOG_DESTROY_WITH_PARENT,
213                                         GTK_MESSAGE_INFO,
214                                         GTK_BUTTONS_OK,
215                                         "You must restart this computer for the changes to take effect.");
216 #if 0
217         g_signal_connect_swapped(dialog, "response",
218                                  G_CALLBACK(gtk_widget_destroy),
219                                  dialog);
220
221         debug("showing dialog\n");
222         gtk_widget_show(dialog);
223 #else
224         gtk_dialog_run(GTK_DIALOG(dialog));
225         gtk_widget_destroy(dialog);
226 #endif
227
228         gtk_label_set_text(GTK_LABEL(state->label_reboot), "Changes will take effect after you restart this computer");
229
230         debug("destroying do_change window\n");
231         gtk_widget_destroy(GTK_WIDGET(state->window_do_change));
232
233         {
234                 uint32_t status;
235                 const char *buffer;
236                 uint16_t type;
237
238                 status = NetGetJoinInformation(NULL, &buffer, &type);
239                 if (status != 0) {
240                         g_print("failed to query status\n");
241                         return;
242                 }
243
244                 debug("got new status: %s\n", buffer);
245 #if 0
246                 SAFE_FREE(state->name_buffer_new);
247                 state->name_buffer_new = strdup(buffer);
248                 SAFE_FREE(buffer);
249                 state->name_type_new = type;
250 #endif
251                 gtk_label_set_text(GTK_LABEL(state->label_current_name_buffer), state->name_buffer_new);
252                 if (state->name_type_new == 3) {
253                         gtk_label_set_text(GTK_LABEL(state->label_current_name_type), "Domain:");
254                 } else {
255                         gtk_label_set_text(GTK_LABEL(state->label_current_name_type), "Workgroup:");
256                 }
257         }
258 }
259
260 static void callback_return_username(GtkWidget *widget,
261                                      gpointer data)
262 {
263         const gchar *entry_text;
264         struct join_state *state = (struct join_state *)data;
265         if (!widget) {
266                 return;
267         }
268         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
269         debug("callback_return_username: %s\n", entry_text);
270         SAFE_FREE(state->account);
271         state->account = strdup(entry_text);
272 }
273
274 static void callback_return_username_and_enter(GtkWidget *widget,
275                                                gpointer data)
276 {
277         const gchar *entry_text;
278         struct join_state *state = (struct join_state *)data;
279         if (!widget) {
280                 return;
281         }
282         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
283         debug("callback_return_username: %s\n", entry_text);
284         SAFE_FREE(state->account);
285         state->account = strdup(entry_text);
286         g_signal_emit_by_name(state->button_ok_creds, "clicked");
287 }
288
289 static void callback_return_password(GtkWidget *widget,
290                                      gpointer data)
291 {
292         const gchar *entry_text;
293         struct join_state *state = (struct join_state *)data;
294         if (!widget) {
295                 return;
296         }
297         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
298 #ifdef DEBUG_PASSWORD
299         debug("callback_return_password: %s\n", entry_text);
300 #else
301         debug("callback_return_password: (not printed)\n");
302 #endif
303         SAFE_FREE(state->password);
304         state->password = strdup(entry_text);
305 }
306
307 static void callback_return_password_and_enter(GtkWidget *widget,
308                                                gpointer data)
309 {
310         const gchar *entry_text;
311         struct join_state *state = (struct join_state *)data;
312         if (!widget) {
313                 return;
314         }
315         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
316 #ifdef DEBUG_PASSWORD
317         debug("callback_return_password: %s\n", entry_text);
318 #else
319         debug("callback_return_password: (not printed)\n");
320 #endif
321         SAFE_FREE(state->password);
322         state->password = strdup(entry_text);
323         g_signal_emit_by_name(state->button_ok_creds, "clicked");
324 }
325
326 static void callback_do_hostname_change(GtkWidget *widget,
327                                         gpointer data)
328 {
329         GtkWidget *dialog;
330         const char *str = NULL;
331
332         struct join_state *state = (struct join_state *)data;
333
334         switch (state->name_type_initial) {
335                 case NetSetupDomainName:
336                         str = "To be implemented: call NetRenameMachineInDomain\n";
337                         break;
338                 case NetSetupWorkgroupName:
339                         str = "To be implemented: call SetComputerNameEx\n";
340                         break;
341                 default:
342                         break;
343         }
344
345         dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
346                                         GTK_DIALOG_DESTROY_WITH_PARENT,
347                                         GTK_MESSAGE_ERROR,
348                                         GTK_BUTTONS_CLOSE,
349                                         str);
350
351         g_signal_connect_swapped(dialog, "response",
352                                  G_CALLBACK(gtk_widget_destroy),
353                                  dialog);
354         gtk_widget_show(dialog);
355 }
356
357 static void callback_do_join(GtkWidget *widget,
358                              gpointer data)
359 {
360         GtkWidget *dialog;
361
362         NET_API_STATUS status;
363         const char *err_str = NULL;
364         uint32_t join_flags = 0;
365         uint32_t unjoin_flags = 0;
366         gboolean domain_join = FALSE;
367         gboolean try_unjoin = FALSE;
368         const char *domain_or_workgroup = NULL;
369
370         struct join_state *state = (struct join_state *)data;
371
372         callback_return_username(state->entry_account, state);
373         callback_return_password(state->entry_password, state);
374
375         if (state->window_creds_prompt) {
376                 gtk_widget_destroy(GTK_WIDGET(state->window_creds_prompt));
377         }
378
379         if (state->name_type_new == NetSetupDomainName) {
380                 domain_join = TRUE;
381                 join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
382                              WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
383                              WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED; /* for testing */
384                 domain_or_workgroup = "domain";
385         } else {
386                 domain_or_workgroup = "workgroup";
387         }
388
389         if ((state->name_type_initial == NetSetupDomainName) &&
390             (state->name_type_new == NetSetupWorkgroupName)) {
391                 try_unjoin = TRUE;
392                 unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
393                                WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
394         }
395
396         debug("callback_do_join: Joining a %s named %s using join_flags 0x%08x ",
397                 domain_or_workgroup,
398                 state->name_buffer_new,
399                 join_flags);
400         if (domain_join) {
401                 debug("as %s ", state->account);
402 #ifdef DEBUG_PASSWORD
403                 debug("with %s ", state->password);
404 #endif
405         }
406         debug("\n");
407         if (try_unjoin) {
408
409                 debug("callback_do_join: Unjoining\n");
410
411                 status = NetUnjoinDomain(NULL,
412                                          state->account,
413                                          state->password,
414                                          unjoin_flags);
415                 if (status != 0) {
416                         err_str = libnetapi_errstr(state->ctx, status);
417                         g_print("callback_do_join: failed to unjoin (%s)\n",
418                                 err_str);
419
420                         dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
421                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
422                                                         GTK_MESSAGE_ERROR,
423                                                         GTK_BUTTONS_CLOSE,
424                                                         "The following error occured attempting to unjoin the %s: \"%s\": %s",
425                                                         domain_or_workgroup,
426                                                         state->name_buffer_new,
427                                                         err_str);
428
429                         g_signal_connect_swapped(dialog, "response",
430                                                  G_CALLBACK(gtk_widget_destroy),
431                                                  dialog);
432
433                         gtk_widget_show(dialog);
434
435                         return;
436                 }
437
438         }
439         status = NetJoinDomain(NULL,
440                                state->name_buffer_new,
441                                NULL,
442                                state->account,
443                                state->password,
444                                join_flags);
445         if (status != 0) {
446                 err_str = libnetapi_errstr(state->ctx, status);
447                 g_print("callback_do_join: failed to join (%s)\n", err_str);
448
449                 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
450                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
451                                                 GTK_MESSAGE_ERROR,
452                                                 GTK_BUTTONS_CLOSE,
453                                                 "The following error occured attempting to join the %s: \"%s\": %s",
454                                                 domain_or_workgroup,
455                                                 state->name_buffer_new,
456                                                 err_str);
457
458                 g_signal_connect_swapped(dialog, "response",
459                                          G_CALLBACK(gtk_widget_destroy),
460                                          dialog);
461
462                 gtk_widget_show(dialog);
463
464                 return;
465         }
466
467         debug("callback_do_join: Successfully joined %s\n",
468                 domain_or_workgroup);
469
470         dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_parent),
471                                         GTK_DIALOG_DESTROY_WITH_PARENT,
472                                         GTK_MESSAGE_INFO,
473                                         GTK_BUTTONS_OK,
474                                         "Welcome to the %s %s.",
475                                         state->name_buffer_new,
476                                         domain_or_workgroup);
477
478         gtk_dialog_run(GTK_DIALOG(dialog));
479         gtk_widget_destroy(dialog);
480
481         callback_do_reboot(NULL, state->window_parent, state);
482 }
483
484 static void callback_creds_prompt(GtkWidget *widget,
485                                   gpointer data)
486 {
487         GtkWidget *window;
488         GtkWidget *box1;
489         GtkWidget *bbox;
490         GtkWidget *button;
491         GtkWidget *label;
492
493         struct join_state *state = (struct join_state *)data;
494
495         debug("callback_creds_prompt:\n");
496
497         state->window_parent = state->window_do_change;
498
499         if (state->hostname_changed) {
500                 return callback_do_hostname_change(NULL, state);
501         }
502
503         if ((state->name_type_initial != NetSetupDomainName) &&
504             (state->name_type_new != NetSetupDomainName)) {
505                 return callback_do_join(NULL, state);
506         }
507
508         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
509
510         gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
511         gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
512         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
513         gtk_widget_set_size_request(GTK_WIDGET(window), 380, 280);
514         gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
515 /*      gtk_window_set_icon_name(GTK_WIDGET(window), GTK_STOCK_DIALOG_AUTHENTICATION); */
516         state->window_creds_prompt = window;
517
518         g_signal_connect(G_OBJECT(window), "delete_event",
519                          G_CALLBACK(callback_do_close), window);
520
521         gtk_container_set_border_width(GTK_CONTAINER(window), 10);
522
523         box1 = gtk_vbox_new(FALSE, 0);
524
525         gtk_container_add(GTK_CONTAINER(window), box1);
526
527         if ((state->name_type_initial == NetSetupDomainName) &&
528             (state->name_type_new == NetSetupWorkgroupName)) {
529                 label = gtk_label_new("Enter the name and password of an account with permission to leave the domain.\n");
530         } else {
531                 label = gtk_label_new("Enter the name and password of an account with permission to join the domain.\n");
532         }
533         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
534         gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
535
536         gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
537
538         gtk_widget_show(label);
539
540         /* USER NAME */
541         label = gtk_label_new("User name:");
542         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
543         gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
544         gtk_widget_show(label);
545
546         state->entry_account = gtk_entry_new();
547         gtk_entry_set_max_length(GTK_ENTRY(state->entry_account), MAX_CRED_LEN);
548         g_signal_connect(G_OBJECT(state->entry_account), "activate",
549                          G_CALLBACK(callback_return_username_and_enter),
550                          (gpointer)state);
551         gtk_editable_select_region(GTK_EDITABLE(state->entry_account),
552                                    0, GTK_ENTRY(state->entry_account)->text_length);
553         gtk_box_pack_start(GTK_BOX(box1), state->entry_account, TRUE, TRUE, 0);
554         gtk_widget_show(state->entry_account);
555
556         /* PASSWORD */
557         label = gtk_label_new("Password:");
558         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
559         gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 0);
560         gtk_widget_show(label);
561
562         state->entry_password = gtk_entry_new();
563         gtk_entry_set_max_length(GTK_ENTRY(state->entry_password), MAX_CRED_LEN);
564         gtk_entry_set_visibility(GTK_ENTRY(state->entry_password), FALSE);
565         g_signal_connect(G_OBJECT(state->entry_password), "activate",
566                          G_CALLBACK(callback_return_password_and_enter),
567                          (gpointer)state);
568         gtk_editable_set_editable(GTK_EDITABLE(state->entry_password), TRUE);
569         gtk_editable_select_region(GTK_EDITABLE(state->entry_password),
570                                    0, GTK_ENTRY(state->entry_password)->text_length);
571         gtk_box_pack_start(GTK_BOX(box1), state->entry_password, TRUE, TRUE, 0);
572         gtk_widget_show(state->entry_password);
573
574         bbox = gtk_hbutton_box_new();
575         gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
576         gtk_container_add(GTK_CONTAINER(box1), bbox);
577         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
578         gtk_box_set_spacing(GTK_BOX(bbox), 10);
579
580         state->button_ok_creds = gtk_button_new_from_stock(GTK_STOCK_OK);
581         gtk_widget_grab_focus(GTK_WIDGET(state->button_ok_creds));
582         gtk_container_add(GTK_CONTAINER(bbox), state->button_ok_creds);
583         g_signal_connect(G_OBJECT(state->button_ok_creds), "clicked",
584                          G_CALLBACK(callback_do_join),
585                          (gpointer)state);
586         gtk_widget_show(state->button_ok_creds);
587
588         button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
589         gtk_container_add(GTK_CONTAINER(bbox), button);
590         g_signal_connect(G_OBJECT(button), "clicked",
591                          G_CALLBACK(callback_do_close), (gpointer) window);
592         gtk_widget_show_all(window);
593 }
594
595 static void callback_enter_hostname_and_unlock(GtkWidget *widget,
596                                                gpointer data)
597 {
598         const gchar *entry_text = NULL;
599         char *str = NULL;
600         struct join_state *state = (struct join_state *)data;
601
602         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
603         debug("callback_enter_hostname_and_unlock: %s\n", entry_text);
604         if (!entry_text || entry_text[0] == 0) {
605                 state->hostname_changed = FALSE;
606                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
607                 return;
608         }
609         if (strcasecmp(state->my_hostname, entry_text) == 0) {
610                 state->hostname_changed = FALSE;
611                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
612                 return;
613         }
614         state->hostname_changed = TRUE;
615         if (state->name_type_initial == NetSetupDomainName) {
616                 asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
617         } else {
618                 asprintf(&str, "%s.", entry_text);
619         }
620         gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
621         free(str);
622
623         if (state->hostname_changed && str && str[0] != 0 && str[0] != '.') {
624                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
625         }
626 }
627
628 static void callback_enter_computer_description_and_unlock(GtkWidget *widget,
629                                                            gpointer data)
630 {
631         const gchar *entry_text = NULL;
632         struct join_state *state = (struct join_state *)data;
633         int string_unchanged = 0;
634
635         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
636         debug("callback_enter_computer_description_and_unlock: %s\n",
637                 entry_text);
638 #if 0
639         if (!entry_text || entry_text[0] == 0) {
640                 string_unchanged = 1;
641                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
642                                          FALSE);
643                 return;
644         }
645 #endif
646         if (entry_text && strcasecmp(state->comment, entry_text) == 0) {
647                 string_unchanged = 1;
648                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply),
649                                          FALSE);
650                 return;
651         }
652
653         gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), TRUE);
654         SAFE_FREE(state->comment_new);
655         state->comment_new = strdup(entry_text);
656
657 }
658
659
660 static void callback_enter_workgroup_and_unlock(GtkWidget *widget,
661                                                 gpointer data)
662 {
663         const gchar *entry_text = NULL;
664         struct join_state *state = (struct join_state *)data;
665
666         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
667         debug("callback_enter_workgroup_and_unlock: %s\n", entry_text);
668         if (!entry_text || entry_text[0] == 0) {
669                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
670                 return;
671         }
672         if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
673                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
674                 return;
675         }
676         gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
677         SAFE_FREE(state->name_buffer_new);
678         state->name_buffer_new = strdup(entry_text);
679         state->name_type_new = NetSetupWorkgroupName;
680 }
681
682 static void callback_enter_domain_and_unlock(GtkWidget *widget,
683                                              gpointer data)
684 {
685         const gchar *entry_text = NULL;
686         struct join_state *state = (struct join_state *)data;
687
688         entry_text = gtk_entry_get_text(GTK_ENTRY(widget));
689         debug("callback_enter_domain_and_unlock: %s\n", entry_text);
690         if (!entry_text || entry_text[0] == 0) {
691                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
692                 return;
693         }
694         if (strcasecmp(state->name_buffer_initial, entry_text) == 0) {
695                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE);
696                 return;
697         }
698         gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), TRUE);
699         SAFE_FREE(state->name_buffer_new);
700         state->name_buffer_new = strdup(entry_text);
701         state->name_type_new = NetSetupDomainName;
702 }
703
704 static void callback_continue(GtkWidget *widget,
705                               gpointer data)
706 {
707         struct join_state *state = (struct join_state *)data;
708
709         gtk_widget_grab_focus(GTK_WIDGET(state->button_ok));
710         g_signal_emit_by_name(state->button_ok, "clicked");
711 }
712
713 static void callback_apply_continue(GtkWidget *widget,
714                                     gpointer data)
715 {
716         struct join_state *state = (struct join_state *)data;
717
718         gtk_widget_grab_focus(GTK_WIDGET(state->button_apply));
719         g_signal_emit_by_name(state->button_apply, "clicked");
720 }
721
722 static void callback_do_join_workgroup(GtkWidget *widget,
723                                        gpointer data)
724 {
725         struct join_state *state = (struct join_state *)data;
726         debug("callback_do_join_workgroup choosen\n");
727         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
728         gtk_widget_grab_focus(GTK_WIDGET(state->entry_workgroup));
729         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
730         callback_enter_workgroup_and_unlock(state->entry_workgroup, state); /* TEST */
731 }
732
733 static void callback_do_join_domain(GtkWidget *widget,
734                                     gpointer data)
735 {
736         struct join_state *state = (struct join_state *)data;
737         debug("callback_do_join_domain choosen\n");
738         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), TRUE);
739         gtk_widget_grab_focus(GTK_WIDGET(state->entry_domain));
740         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), FALSE);
741         callback_enter_domain_and_unlock(state->entry_domain, state); /* TEST */
742 }
743
744 static void callback_do_change(GtkWidget *widget,
745                                gpointer data)
746 {
747         GtkWidget *window;
748         GtkWidget *box1;
749         GtkWidget *bbox;
750         GtkWidget *button_workgroup;
751         GtkWidget *button_domain;
752         GtkWidget *button;
753         GtkWidget *label;
754         GtkWidget *frame_horz;
755         GtkWidget *vbox;
756         GtkWidget *entry;
757         GSList *group;
758
759         struct join_state *state = (struct join_state *)data;
760
761         debug("callback_do_change called\n");
762
763         if (state->server_role == 3) {
764                 GtkWidget *dialog;
765                 dialog = gtk_message_dialog_new(GTK_WINDOW(state->window_main),
766                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
767                                                 GTK_MESSAGE_ERROR,
768                                                 GTK_BUTTONS_OK,
769                                                 "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.");
770                 g_signal_connect_swapped(dialog, "response",
771                                          G_CALLBACK(gtk_widget_destroy),
772                                          dialog);
773
774                 gtk_widget_show(dialog);
775                 return;
776         }
777
778         state->button_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
779         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
780
781         gtk_window_set_title(GTK_WINDOW(window), "Computer Name Changes");
782         gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
783         gtk_widget_set_size_request(GTK_WIDGET(window), 480, 500); /* breite * höhe */
784         gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
785
786         g_signal_connect(G_OBJECT(window), "delete_event",
787                          G_CALLBACK(callback_do_close), window);
788
789         gtk_container_set_border_width(GTK_CONTAINER(window), 10);
790
791         box1 = gtk_vbox_new(FALSE, 0);
792         gtk_container_add(GTK_CONTAINER(window), box1);
793
794         label = gtk_label_new("You can change the name and membership of this computer. Changes may affect access to network ressources.");
795         gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
796         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
797         gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
798         gtk_widget_show(label);
799
800         /* COMPUTER NAME */
801         label = gtk_label_new("Computer name:");
802         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
803         gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
804         gtk_widget_show(label);
805
806         state->label_full_computer_name = gtk_label_new(NULL);
807         {
808                 entry = gtk_entry_new();
809                 gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_NETBIOS_NAME_LEN);
810                 g_signal_connect(G_OBJECT(entry), "changed",
811                                  G_CALLBACK(callback_enter_hostname_and_unlock),
812                                  (gpointer)state);
813                 gtk_entry_set_text(GTK_ENTRY(entry), state->my_hostname);
814                 gtk_editable_select_region(GTK_EDITABLE(entry),
815                                            0, GTK_ENTRY(entry)->text_length);
816
817                 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
818                 gtk_box_pack_start(GTK_BOX(box1), entry, TRUE, TRUE, 0);
819                 gtk_widget_show(entry);
820         }
821
822         /* FULL COMPUTER NAME */
823         label = gtk_label_new("Full computer name:");
824         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
825         gtk_box_pack_start(GTK_BOX(box1), label, TRUE, TRUE, 0);
826         gtk_widget_show(label);
827
828         {
829                 const gchar *entry_text;
830                 char *str = NULL;
831                 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
832                 if (state->name_type_initial == NetSetupDomainName) {
833                         asprintf(&str, "%s.%s", entry_text, state->my_dnsdomain);
834                 } else {
835                         asprintf(&str, "%s.", entry_text);
836                 }
837                 gtk_label_set_text(GTK_LABEL(state->label_full_computer_name), str);
838                 free(str);
839                 gtk_misc_set_alignment(GTK_MISC(state->label_full_computer_name), 0, 0);
840                 gtk_box_pack_start(GTK_BOX(box1), state->label_full_computer_name, TRUE, TRUE, 0);
841                 gtk_widget_show(state->label_full_computer_name);
842         }
843
844         /* BOX */
845         frame_horz = gtk_frame_new ("Member Of");
846         gtk_box_pack_start(GTK_BOX(box1), frame_horz, TRUE, TRUE, 10);
847
848         vbox = gtk_vbox_new(FALSE, 0);
849         gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
850         gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
851
852         /* TWO ENTRIES */
853         state->entry_workgroup = gtk_entry_new();
854         state->entry_domain = gtk_entry_new();
855
856         /* DOMAIN */
857         button_domain = gtk_radio_button_new_with_label(NULL, "Domain");
858         if (state->name_type_initial == NetSetupDomainName) {
859                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_domain), TRUE);
860         }
861         gtk_box_pack_start(GTK_BOX(vbox), button_domain, TRUE, TRUE, 0);
862         g_signal_connect(G_OBJECT(button_domain), "clicked",
863                          G_CALLBACK(callback_do_join_domain),
864                          (gpointer)state);
865
866         {
867                 gtk_entry_set_max_length(GTK_ENTRY(state->entry_domain), 50);
868                 g_signal_connect(G_OBJECT(state->entry_domain), "changed",
869                                  G_CALLBACK(callback_enter_domain_and_unlock),
870                                  (gpointer)state);
871                 g_signal_connect(G_OBJECT(state->entry_domain), "activate",
872                                  G_CALLBACK(callback_continue),
873                                  (gpointer)state);
874                 if (state->name_type_initial == NetSetupDomainName) {
875                         gtk_entry_set_text(GTK_ENTRY(state->entry_domain), state->name_buffer_initial);
876                         gtk_widget_set_sensitive(state->entry_workgroup, FALSE);
877                         gtk_widget_set_sensitive(state->entry_domain, TRUE);
878                 }
879                 gtk_editable_set_editable(GTK_EDITABLE(state->entry_domain), TRUE);
880                 gtk_box_pack_start(GTK_BOX(vbox), state->entry_domain, TRUE, TRUE, 0);
881                 gtk_widget_show(state->entry_domain);
882         }
883         gtk_widget_show(button_domain);
884
885         /* WORKGROUP */
886         group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button_domain));
887         button_workgroup = gtk_radio_button_new_with_label(group, "Workgroup");
888         if (state->name_type_initial == NetSetupWorkgroupName) {
889                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_workgroup), TRUE);
890         }
891         gtk_box_pack_start(GTK_BOX(vbox), button_workgroup, TRUE, TRUE, 0);
892         g_signal_connect(G_OBJECT(button_workgroup), "clicked",
893                          G_CALLBACK(callback_do_join_workgroup),
894                          (gpointer)state);
895         {
896                 gtk_entry_set_max_length(GTK_ENTRY(state->entry_workgroup), MAX_NETBIOS_NAME_LEN);
897                 g_signal_connect(G_OBJECT(state->entry_workgroup), "changed",
898                                  G_CALLBACK(callback_enter_workgroup_and_unlock),
899                                  (gpointer)state);
900                 g_signal_connect(G_OBJECT(state->entry_workgroup), "activate",
901                                  G_CALLBACK(callback_continue),
902                                  (gpointer)state);
903
904                 if (state->name_type_initial == NetSetupWorkgroupName) {
905                         gtk_entry_set_text(GTK_ENTRY(state->entry_workgroup), state->name_buffer_initial);
906                         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_domain), FALSE);
907                         gtk_widget_set_sensitive(GTK_WIDGET(state->entry_workgroup), TRUE);
908                 }
909                 gtk_box_pack_start(GTK_BOX(vbox), state->entry_workgroup, TRUE, TRUE, 0);
910                 gtk_widget_show(state->entry_workgroup);
911         }
912         gtk_widget_show(button_workgroup);
913
914         /* BUTTONS */
915         bbox = gtk_hbutton_box_new();
916         gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
917         gtk_container_add(GTK_CONTAINER(box1), bbox);
918         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
919         gtk_box_set_spacing(GTK_BOX(bbox), 10);
920
921         state->window_do_change = window;
922         gtk_widget_set_sensitive(GTK_WIDGET(state->button_ok), FALSE); /* !!! */
923         gtk_container_add(GTK_CONTAINER(bbox), state->button_ok);
924         g_signal_connect(G_OBJECT(state->button_ok), "clicked",
925                          G_CALLBACK(callback_creds_prompt),
926                          (gpointer)state);
927
928         button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
929         gtk_container_add(GTK_CONTAINER(bbox), button);
930         g_signal_connect(G_OBJECT(button), "clicked",
931                          G_CALLBACK(callback_do_close),
932                          (gpointer)window);
933
934         gtk_widget_show_all(window);
935
936 }
937
938 static void callback_do_about(GtkWidget *widget,
939                              gpointer data)
940 {
941         GdkPixbuf *logo;
942         GError    *error = NULL;
943
944         debug("callback_do_about called\n");
945
946         logo = gdk_pixbuf_new_from_file(SAMBA_IMAGE_PATH,
947                                         &error);
948         if (logo == NULL) {
949                 g_print("failed to load logo from %s: %s\n",
950                         SAMBA_IMAGE_PATH, error->message);
951         }
952
953         gtk_show_about_dialog(data,
954                               "name", "Samba",
955                               "version", "3.2.0pre2-GIT-904a90-test",
956                               "copyright", "Copyright Andrew Tridgell and the Samba Team 1992-2007",
957                               "website", "http://www.samba.org",
958                               "license", "GPLv3",
959                               "logo", logo,
960                               "comments", "Samba gtk domain join utility",
961                               NULL);
962 }
963
964 static int draw_main_window(struct join_state *state)
965 {
966         GtkWidget *window;
967         GtkWidget *button;
968         GtkWidget *label;
969         GtkWidget *main_vbox;
970         GtkWidget *vbox;
971         GtkWidget *hbox;
972         GtkWidget *bbox;
973         GtkWidget *image;
974         GtkWidget *table;
975         GtkWidget *entry;
976         GdkPixbuf *icon;
977         GError    *error = NULL;
978
979         icon = gdk_pixbuf_new_from_file(SAMBA_ICON_PATH,
980                                         &error);
981         if (icon == NULL) {
982                 g_print("failed to load logo from %s : %s\n",
983                         SAMBA_ICON_PATH, error->message);
984         }
985
986 #if 1
987         image = gtk_image_new_from_file(SAMBA_IMAGE_PATH);
988 #else
989         image = gtk_image_new_from_file("/usr/share/pixmaps/redhat-system_settings.png");
990 #endif
991
992         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
993         state->window_main = window;
994
995         gtk_window_set_title(GTK_WINDOW(window), "Samba - Join Domain dialogue");
996         gtk_widget_set_size_request(GTK_WIDGET(window), 600, 600); /* breite * höhe */
997         gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
998         gtk_window_set_icon_from_file(GTK_WINDOW(window), SAMBA_ICON_PATH, NULL);
999
1000         g_signal_connect(G_OBJECT(window), "delete_event",
1001                          G_CALLBACK(callback_delete_event), NULL);
1002
1003         gtk_container_set_border_width(GTK_CONTAINER(window), 10);
1004
1005         main_vbox = gtk_vbox_new(FALSE, 10);
1006         gtk_container_add(GTK_CONTAINER(window), main_vbox);
1007
1008 #if 0
1009         gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10);
1010         gtk_widget_show(image);
1011 #endif
1012         /* Hbox */
1013         hbox = gtk_hbox_new(FALSE, 10);
1014         gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
1015
1016         {
1017 /*              gtk_box_pack_start(GTK_BOX(main_vbox), image, TRUE, TRUE, 10); */
1018                 gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
1019                 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 10);
1020                 gtk_widget_show(image);
1021
1022                 /* Label */
1023                 label = gtk_label_new("Samba uses the following information to identify your computer on the network.");
1024                 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1025                 gtk_widget_set_size_request(GTK_WIDGET(label), 500, 40);
1026                 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1027                 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1028                 gtk_widget_show(label);
1029         }
1030
1031         gtk_widget_show(hbox);
1032
1033         vbox = gtk_vbox_new(FALSE, 0);
1034         gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
1035         gtk_container_add(GTK_CONTAINER(main_vbox), vbox);
1036
1037         /* Table */
1038         table = gtk_table_new(6, 3, TRUE);
1039         gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1040         gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1041         gtk_container_add(GTK_CONTAINER(vbox), table);
1042
1043         {
1044                 /* Label */
1045                 label = gtk_label_new("Computer description:");
1046 /*              gtk_misc_set_alignment(GTK_MISC(label), 0, 0); */
1047                 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1048                 gtk_widget_show(label);
1049
1050                 state->button_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1051
1052                 /* Entry */
1053                 entry = gtk_entry_new();
1054                 gtk_entry_set_max_length(GTK_ENTRY(entry), 256);
1055                 g_signal_connect(G_OBJECT(entry), "changed",
1056                                  G_CALLBACK(callback_enter_computer_description_and_unlock),
1057                                  state);
1058                 g_signal_connect(G_OBJECT(entry), "activate",
1059                                  G_CALLBACK(callback_apply_continue),
1060                                  (gpointer)state);
1061
1062                 gtk_entry_set_text(GTK_ENTRY(entry), (char *)state->comment);
1063                 gtk_editable_set_editable(GTK_EDITABLE(entry), TRUE); /* ! */
1064                 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 3, 0, 1);
1065                 gtk_widget_show(entry);
1066         }
1067
1068         /* Label */
1069         label = gtk_label_new("For example: \"Samba \%v\".");
1070         gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1071         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1072         gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 1, 2);
1073         gtk_widget_show(label);
1074
1075         /* Label */
1076         label = gtk_label_new("Full computer name:");
1077         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1078         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1079         gtk_widget_show(label);
1080
1081         {
1082                 /* Label */
1083                 char *str = NULL;
1084                 if (state->name_type_initial == NetSetupDomainName) {
1085                         asprintf(&str, "%s.%s", state->my_hostname,
1086                                  state->my_dnsdomain);
1087                 } else {
1088                         asprintf(&str, "%s.", state->my_hostname);
1089                 }
1090
1091                 label = gtk_label_new(str);
1092                 SAFE_FREE(str);
1093                 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1094                 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 2, 3);
1095                 gtk_widget_show(label);
1096         }
1097
1098         /* Label */
1099         if (state->name_type_initial == NetSetupDomainName) {
1100                 label = gtk_label_new("Domain:");
1101         } else {
1102                 label = gtk_label_new("Workgroup:");
1103         }
1104         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1105         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
1106         gtk_widget_show(label);
1107         state->label_current_name_type = label;
1108
1109         /* Label */
1110         label = gtk_label_new(state->name_buffer_initial);
1111         gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1112         gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 3, 3, 4);
1113         gtk_widget_show(label);
1114         state->label_current_name_buffer = label;
1115
1116         {
1117                 hbox = gtk_hbox_new(FALSE, 0);
1118                 gtk_container_add(GTK_CONTAINER(vbox), hbox);
1119                 label = gtk_label_new("To rename this computer or join a domain, click Change.");
1120                 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1121
1122
1123         }
1124
1125         /* bbox */
1126         bbox = gtk_hbutton_box_new();
1127         gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
1128         gtk_container_add(GTK_CONTAINER(hbox), bbox);
1129         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1130         gtk_box_set_spacing(GTK_BOX(bbox), 10);
1131
1132         button = gtk_button_new_with_mnemonic("Ch_ange");
1133         g_signal_connect(G_OBJECT(button), "clicked",
1134                          G_CALLBACK(callback_do_change),
1135                          (gpointer)state);
1136         gtk_box_pack_start(GTK_BOX(bbox), button, TRUE, TRUE, 0);
1137         gtk_widget_show(button);
1138
1139         /* Label (hidden) */
1140         state->label_reboot = gtk_label_new(NULL);
1141         gtk_label_set_line_wrap(GTK_LABEL(state->label_reboot), TRUE);
1142         gtk_misc_set_alignment(GTK_MISC(state->label_reboot), 0, 0);
1143         gtk_box_pack_start(GTK_BOX(vbox), state->label_reboot, TRUE, TRUE, 0);
1144         gtk_widget_show(state->label_reboot);
1145
1146 #if 0
1147         gtk_box_pack_start(GTK_BOX(vbox),
1148            create_bbox(window, TRUE, NULL, 10, 85, 20, GTK_BUTTONBOX_END),
1149                       TRUE, TRUE, 5);
1150 #endif
1151         {
1152
1153                 GtkWidget *frame;
1154                 GtkWidget *bbox2;
1155                 GtkWidget *button2;
1156
1157                 frame = gtk_frame_new(NULL);
1158                 bbox2 = gtk_hbutton_box_new();
1159
1160                 gtk_container_set_border_width(GTK_CONTAINER(bbox2), 5);
1161                 gtk_container_add(GTK_CONTAINER(frame), bbox2);
1162
1163                 /* Set the appearance of the Button Box */
1164                 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox2), GTK_BUTTONBOX_END);
1165                 gtk_box_set_spacing(GTK_BOX(bbox2), 10);
1166                 /*gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox2), child_w, child_h);*/
1167
1168                 button2 = gtk_button_new_from_stock(GTK_STOCK_OK);
1169                 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1170                 g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(callback_do_exit), state);
1171
1172                 button2 = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1173                 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1174                 g_signal_connect(G_OBJECT(button2), "clicked",
1175                                  G_CALLBACK(callback_delete_event),
1176                                  window);
1177
1178                 gtk_container_add(GTK_CONTAINER(bbox2), state->button_apply);
1179                 g_signal_connect(G_OBJECT(state->button_apply), "clicked",
1180                                  G_CALLBACK(callback_apply_description_change),
1181                                  state);
1182                 gtk_widget_set_sensitive(GTK_WIDGET(state->button_apply), FALSE);
1183
1184                 button2 = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
1185                 gtk_container_add(GTK_CONTAINER(bbox2), button2);
1186                 g_signal_connect(G_OBJECT(button2), "clicked",
1187                                  G_CALLBACK(callback_do_about),
1188                                  window);
1189
1190                 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
1191         }
1192
1193         gtk_widget_show_all(window);
1194
1195         return 0;
1196 }
1197
1198 static int init_join_state(struct join_state **state)
1199 {
1200         struct join_state *s;
1201
1202         s = malloc(sizeof(struct join_state));
1203         if (!s) {
1204                 return -1;
1205         }
1206
1207         memset(s, '\0', sizeof(struct join_state));
1208
1209         *state = s;
1210
1211         return 0;
1212 }
1213
1214 static int initialize_join_state(struct join_state *state,
1215                                  const char *debug_level)
1216 {
1217         struct libnetapi_ctx *ctx = NULL;
1218         NET_API_STATUS status = 0;
1219
1220         status = libnetapi_init(&ctx);
1221         if (status) {
1222                 return status;
1223         }
1224
1225         if (debug_level) {
1226                 libnetapi_set_debuglevel(ctx, debug_level);
1227         }
1228
1229         {
1230                 char my_hostname[HOST_NAME_MAX];
1231                 const char *p = NULL;
1232                 if (gethostname(my_hostname, sizeof(my_hostname)) == -1) {
1233                         return -1;
1234                 }
1235
1236                 state->my_fqdn = strdup(my_hostname);
1237                 if (!state->my_fqdn) {
1238                         return -1;
1239                 }
1240
1241                 p = strchr(my_hostname, '.');
1242                 if (p) {
1243                         my_hostname[strlen(my_hostname) - strlen(p)] = '\0';
1244                         state->my_hostname = strdup(my_hostname);
1245                         if (!state->my_hostname) {
1246                                 return -1;
1247                         }
1248                         p++;
1249                         state->my_dnsdomain = strdup(p);
1250                         if (!state->my_dnsdomain) {
1251                                 return -1;
1252                         }
1253                 }
1254         }
1255
1256         {
1257                 const char *buffer = NULL;
1258                 uint16_t type = 0;
1259                 status = NetGetJoinInformation(NULL, &buffer, &type);
1260                 if (status) {
1261                         return status;
1262                 }
1263                 state->name_buffer_initial = (char *)buffer;
1264                 state->name_type_initial = type;
1265         }
1266
1267         {
1268                 struct srvsvc_NetSrvInfo1005 *info1005 = NULL;
1269                 uint8_t *buffer = NULL;
1270
1271                 status = NetServerGetInfo(NULL, 1005, &buffer);
1272                 if (status) {
1273                         return status;
1274                 }
1275
1276                 info1005 = (struct srvsvc_NetSrvInfo1005 *)buffer;
1277
1278                 state->comment = strdup(info1005->comment);
1279                 if (!state->comment) {
1280                         return -1;
1281                 }
1282         }
1283 #if 0
1284         {
1285                 struct srvsvc_NetSrvInfo100 *info100 = NULL;
1286                 uint8_t *buffer = NULL;
1287
1288                 status = NetServerGetInfo(NULL, 100, &buffer);
1289                 if (status) {
1290                         return status;
1291                 }
1292
1293                 info100 = (struct srvsvc_NetSrvInfo100 *)buffer;
1294
1295                 state->comment = strdup(info100->comment);
1296                 if (!state->comment) {
1297                         return -1;
1298                 }
1299         }
1300 #endif
1301
1302         state->ctx = ctx;
1303
1304         return 0;
1305 }
1306
1307 int main(int argc, char **argv)
1308 {
1309         GOptionContext *context = NULL;
1310         static const char *debug_level = NULL;
1311         struct join_state *state = NULL;
1312         GError *error = NULL;
1313         int ret = 0;
1314
1315         static GOptionEntry entries[] = {
1316                 { "debug", 'd', 0, G_OPTION_ARG_STRING, &debug_level, "Debug level (for samba)", "N" },
1317                 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", 0 },
1318                 { NULL }
1319         };
1320
1321         context = g_option_context_new("- Samba domain join utility");
1322         g_option_context_add_main_entries(context, entries, NULL);
1323 /*      g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); */
1324         g_option_context_add_group(context, gtk_get_option_group(TRUE));
1325         g_option_context_parse(context, &argc, &argv, &error);
1326
1327         gtk_init(&argc, &argv);
1328         g_set_application_name("Samba");
1329
1330         ret = init_join_state(&state);
1331         if (ret) {
1332                 return ret;
1333         }
1334
1335         ret = initialize_join_state(state, debug_level);
1336         if (ret) {
1337                 return ret;
1338         }
1339
1340         draw_main_window(state);
1341
1342         gtk_main();
1343
1344         do_cleanup(state);
1345
1346         return 0;
1347 }