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