Crossfire Client, Trunk  R18666
/home/leaf/crossfire/client/trunk/gtk-v2/src/account.c
Go to the documentation of this file.
00001 const char * const rcsid_gtk2_account_c =
00002     "$Id: account.c 14486 2011-05-23 17:57:22Z ryo_saeba $";
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2010 Mark Wedel & Crossfire Development Team
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022     The author can be reached via e-mail to crossfire@metalforge.org
00023 */
00024 
00030 #ifdef HAVE_CONFIG_H
00031 #  include <config.h>
00032 #endif
00033 
00034 #include <gtk/gtk.h>
00035 #include <glade/glade.h>
00036 #include <ctype.h>
00037 
00038 #include "client.h"
00039 
00040 #include "image.h"
00041 
00042 #include "main.h"
00043 #include "gtk2proto.h"
00044 #include "metaserver.h"
00045 
00046 static GtkWidget *add_character_window, *choose_char_window,
00047  *create_account_window, *login_window, *account_password_window;
00048 
00049 /* These are in the login_window */
00050 static GtkWidget *button_login, *button_create_account,
00051     *button_go_metaserver, *button_exit_client,
00052     *entry_account_name,
00053     *entry_account_password, *label_account_login_status;
00054 
00055 /* These are in the create_account_window */
00056 static GtkWidget *button_new_create_account, *button_new_cancel,
00057     *entry_new_account_name,
00058     *entry_new_account_password, *entry_new_confirm_password,
00059     *label_create_account_status;
00060 
00061 /* These are in the choose_character window */
00062 static GtkWidget *button_play_character, *button_create_character,
00063     *button_add_character, *button_return_login, *button_account_password,
00064     *treeview_choose_character;
00065 
00066 /* These are in the new_character window */
00067 static GtkWidget *entry_new_character_name, *new_character_window,
00068     *label_new_char_status, *button_create_new_char,
00069     *button_new_char_cancel;
00070 
00071 /* These are in the account_password window */
00072 static GtkWidget *entry_account_password_current, *entry_account_password_new,
00073     *entry_account_password_confirm, *button_account_password_confirm,
00074     *button_account_password_cancel, *label_account_password_status;
00075 
00076 GtkListStore    *character_store;
00077 
00078 /* create_char.c also uses this */
00079 char account_password[256];
00080 
00081 /* This enum just maps the columns in the list store to their position.
00082  */
00083 enum {CHAR_IMAGE, CHAR_NAME, CHAR_CLASS, CHAR_RACE, CHAR_LEVEL, CHAR_PARTY,
00084       CHAR_MAP, CHAR_ICON};
00085 #define  CHAR_NUM_COLUMNS 8
00086 
00087 /* These are in the add_character window */
00088 static GtkWidget *button_do_add_character,
00089     *button_return_character_select, *entry_character_name,
00090     *entry_character_password, *label_add_status;
00091 
00092 GtkTextBuffer *textbuf_motd, *textbuf_news, *textbuf_rules_account,
00093     *textbuf_rules_char;
00094 
00095 /* These are used as offsets for num_text_views - we share the drawing code in
00096  * info.c if more textviews are added, note that NUM_TEXT_VIEWS in info.c
00097  * needs to be increased.
00098  */
00099 #define TEXTVIEW_MOTD           0
00100 #define TEXTVIEW_NEWS           1
00101 #define TEXTVIEW_RULES_ACCOUNT  2
00102 #define TEXTVIEW_RULES_CHAR     3
00103 
00104 Info_Pane login_pane[4];
00105 
00106 extern int num_text_views;
00107 
00108 static int has_init=0;
00109 
00116 void hide_all_login_windows(void)
00117 {
00118     extern GtkWidget *treeview_look;
00119 
00120     if (has_init) {
00121         /* If we have not initialized, nothing to hide */
00122         gtk_widget_hide(login_window);
00123         gtk_widget_hide(add_character_window);
00124         gtk_widget_hide(choose_char_window);
00125         gtk_widget_hide(create_account_window);
00126         gtk_widget_hide(new_character_window);
00127         gtk_widget_hide(account_password_window);
00128         create_character_window_hide(); /* create_char.c */
00129 
00130         /* If the player has started playing (this function being called from
00131          * AddMeSuccess), we want to make sure that the extended command entry
00132          * widget is not activated - we want normal command entry.  Where this
00133          * shows up is if the player was playing before and uses a savebed -
00134          * now the last thing activated is that entry widget.
00135          */
00136         gtk_widget_grab_focus(GTK_WIDGET(treeview_look));
00137     }
00138 }
00139 
00148 gboolean on_window_delete_event(GtkWidget *window, gpointer *user_data) {
00149     return TRUE;
00150 }
00151 
00152 /*****************************************************************************
00153  * New character window functions
00154  *****************************************************************************/
00155 
00167 void create_new_character_failure(char *message)
00168 {
00169     GtkWidget *dialog;
00170 
00171     dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
00172                                     GTK_BUTTONS_OK,
00173                                     "Error: %s", message);
00174     gtk_dialog_run(GTK_DIALOG(dialog));
00175     gtk_widget_destroy(dialog);
00176 
00177 }
00178 
00182 static void create_new_character(void)
00183 {
00184     const char *name;
00185     uint8 buf[MAX_BUF];
00186     SockList sl;
00187 
00188     SockList_Init(&sl, buf);
00189 
00190     name =  gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
00191 
00192     if (!name || *name == 0) {
00193         gtk_label_set_text(GTK_LABEL(label_new_char_status),
00194                            "You must enter a character name.");
00195         return;
00196     } else {
00197         gtk_label_set_text(GTK_LABEL(label_new_char_status), "");
00198 
00199         SockList_AddString(&sl, "createplayer ");
00200         SockList_AddChar(&sl, strlen(name));
00201         SockList_AddString(&sl, name);
00202         SockList_AddChar(&sl, strlen(account_password));
00203         SockList_AddString(&sl, account_password);
00204         SockList_Send(&sl, csocket.fd);
00205     }
00206 }
00207 
00213 void
00214 on_button_create_new_char_clicked(GtkButton *button, gpointer user_data)
00215 {
00216     create_new_character();
00217 }
00218 
00225 void on_entry_new_character_name(GtkEntry *entry, gpointer user_data)
00226 {
00227     create_new_character();
00228 }
00229 
00236 void
00237 on_button_new_char_cancel_clicked(GtkButton *button, gpointer user_data)
00238 {
00239     gtk_widget_hide(new_character_window);
00240     gtk_widget_show(choose_char_window);
00241 }
00242 
00246 static void init_new_character_window(void)
00247 {
00248     GladeXML *xml_tree;
00249 
00250     new_character_window =
00251          glade_xml_get_widget(dialog_xml, "new_character_window");
00252 
00253     gtk_window_set_transient_for(
00254         GTK_WINDOW(new_character_window), GTK_WINDOW(window_root));
00255 
00256     xml_tree = glade_get_widget_tree(GTK_WIDGET(new_character_window));
00257 
00258     button_create_new_char =
00259         glade_xml_get_widget(dialog_xml,"button_create_new_char");
00260     button_new_char_cancel =
00261         glade_xml_get_widget(dialog_xml,"button_new_char_cancel");
00262     entry_new_character_name =
00263         glade_xml_get_widget(dialog_xml,"entry_new_character_name");
00264     label_new_char_status =
00265         glade_xml_get_widget(dialog_xml,"label_new_char_status");
00266 
00267     g_signal_connect((gpointer) new_character_window, "delete_event",
00268                      G_CALLBACK(on_window_delete_event), NULL);
00269     g_signal_connect((gpointer) button_create_new_char, "clicked",
00270                      G_CALLBACK(on_button_create_new_char_clicked), NULL);
00271     g_signal_connect((gpointer) button_new_char_cancel, "clicked",
00272                      G_CALLBACK(on_button_new_char_cancel_clicked), NULL);
00273     g_signal_connect((gpointer) entry_new_character_name, "activate",
00274                      G_CALLBACK(on_entry_new_character_name), NULL);
00275 }
00276 
00277 /******************************************************************************
00278  * add_character_window functions
00279  *****************************************************************************/
00280 
00287 static void add_character_to_account(const char *name, const char *password, int force)
00288 {
00289     SockList sl;
00290     uint8 buf[MAX_BUF];
00291 
00292     if (!name || !password || *name == 0 || *password == 0) {
00293         gtk_label_set_text(GTK_LABEL(label_add_status),
00294                       "You must enter both a name and password!");
00295     } else {
00296         gtk_label_set_text(GTK_LABEL(label_add_status), "");
00297 
00298         SockList_Init(&sl, buf);
00299         SockList_AddString(&sl, "accountaddplayer ");
00300         SockList_AddChar(&sl, force);
00301         SockList_AddChar(&sl, strlen(name));
00302         SockList_AddString(&sl, name);
00303         SockList_AddChar(&sl, strlen(password));
00304         SockList_AddString(&sl, password);
00305         SockList_Send(&sl, csocket.fd);
00306     }
00307 }
00308 
00320 void account_add_character_failure(char *message)
00321 {
00322     char *cp;
00323     int retry;
00324 
00325     retry = atoi(message);
00326     cp = strchr(message,' ');
00327     if (cp) {
00328         cp++;
00329     } else
00330         cp=message;
00331 
00332     if (!retry) {
00333         gtk_label_set_text(GTK_LABEL(label_add_status), cp);
00334     } else {
00335         /* In this case, we can retry it and it should work if we set force.
00336          * So bring up a dialog, as the user what to do - if they enter yes,
00337          * we use force.  If not, we clear the entry fields and just continue
00338          * onward.
00339          */
00340         GtkWidget *dialog;
00341         int result;
00342         const char *name, *password;
00343 
00344         /* Bring up a dialog window */
00345         dialog =
00346             gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
00347                                    GTK_BUTTONS_YES_NO, "%s\n%s", cp, "Apply anyways?");
00348         result = gtk_dialog_run(GTK_DIALOG(dialog));
00349         gtk_widget_destroy(dialog);
00350 
00351         if (result == GTK_RESPONSE_YES ) {
00352             name =  gtk_entry_get_text(GTK_ENTRY(entry_character_name));
00353             password =  gtk_entry_get_text(GTK_ENTRY(entry_character_password));
00354             add_character_to_account(name, password, 1);
00355         } else {
00356             gtk_entry_set_text(GTK_ENTRY(entry_character_name), "");
00357             gtk_entry_set_text(GTK_ENTRY(entry_character_password), "");
00358             gtk_widget_grab_focus(entry_character_name);
00359         }
00360     }
00361 }
00362 
00370 void
00371 on_button_do_add_character_clicked(GtkButton *button, gpointer user_data)
00372 {
00373     add_character_to_account(
00374         gtk_entry_get_text(GTK_ENTRY(entry_character_name)),
00375             gtk_entry_get_text(GTK_ENTRY(entry_character_password)), 0);
00376 }
00377 
00385 void
00386 on_button_return_character_select_clicked(GtkButton *button, gpointer user_data)
00387 {
00388     gtk_widget_hide(add_character_window);
00389     gtk_widget_show(choose_char_window);
00390 }
00391 
00400 void on_entry_character(GtkEntry *entry, gpointer user_data) {
00401     const char *name, *password;
00402 
00403     name =  gtk_entry_get_text(GTK_ENTRY(entry_character_name));
00404     password =  gtk_entry_get_text(GTK_ENTRY(entry_character_password));
00405 
00406     if (name && name[0] && password && password[0]) {
00407         add_character_to_account(name, password, 0);
00408     } else {
00409         const char *cp;
00410 
00411         /* First case - this widget is empty - do nothing */
00412         cp = gtk_entry_get_text(entry);
00413         if (!cp || !cp[0]) return;
00414 
00415         /* In this case, this widget is not empty - means the other one is.
00416          */
00417         if (entry == GTK_ENTRY(entry_character_name))
00418             gtk_widget_grab_focus(entry_character_password);
00419         else
00420             gtk_widget_grab_focus(entry_character_name);
00421     }
00422 }
00423 
00427 static void init_add_character_window(void) {
00428     GladeXML *xml_tree;
00429 
00430     add_character_window =
00431          glade_xml_get_widget(dialog_xml, "add_character_window");
00432 
00433     gtk_window_set_transient_for(
00434         GTK_WINDOW(add_character_window), GTK_WINDOW(window_root));
00435 
00436     xml_tree = glade_get_widget_tree(GTK_WIDGET(add_character_window));
00437 
00438     button_do_add_character =
00439         glade_xml_get_widget(dialog_xml,"button_do_add_character");
00440     button_return_character_select =
00441         glade_xml_get_widget(dialog_xml,"button_return_character_select");
00442     entry_character_name =
00443         glade_xml_get_widget(dialog_xml,"entry_character_name");
00444     entry_character_password =
00445         glade_xml_get_widget(dialog_xml,"entry_character_password");
00446     label_add_status =
00447         glade_xml_get_widget(dialog_xml,"label_add_status");
00448 
00449     g_signal_connect((gpointer) add_character_window, "delete_event",
00450                      G_CALLBACK(on_window_delete_event), NULL);
00451     g_signal_connect((gpointer) button_do_add_character, "clicked",
00452                      G_CALLBACK(on_button_do_add_character_clicked), NULL);
00453     g_signal_connect((gpointer) button_return_character_select, "clicked",
00454                      G_CALLBACK(on_button_return_character_select_clicked), NULL);
00455     g_signal_connect((gpointer) entry_character_name, "activate",
00456                      G_CALLBACK(on_entry_character), NULL);
00457     g_signal_connect((gpointer) entry_character_password, "activate",
00458                      G_CALLBACK(on_entry_character), NULL);
00459 }
00460 
00461 /*****************************************************************************
00462  * choose_char_window
00463  ****************************************************************************/
00464 
00471 void choose_character_init(void)
00472 {
00473     gtk_widget_hide(login_window);
00474     gtk_widget_hide(add_character_window);
00475     gtk_widget_hide(create_account_window);
00476     gtk_widget_show(choose_char_window);
00477 
00478     /* Store any old/stale entries */
00479     gtk_list_store_clear(character_store);
00480 }
00481 
00489 void choose_char_window_show()
00490 {
00491     gtk_widget_show(choose_char_window);
00492 }
00493 
00494 
00499 static void play_character(const char *name)
00500 {
00501     SockList sl;
00502     uint8 buf[MAX_BUF];
00503 
00504     SockList_Init(&sl, buf);
00505     SockList_AddString(&sl, "accountplay ");
00506     SockList_AddString(&sl, name);
00507     SockList_Send(&sl, csocket.fd);
00508 }
00509 
00516 void
00517 on_button_play_character_clicked(GtkButton *button, gpointer user_data)
00518 {
00519     GtkTreeSelection *selected;
00520     GtkTreeModel    *model;
00521     GtkTreeIter iter;
00522     char *name;
00523 
00524     selected = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_choose_character));
00525 
00526     if (gtk_tree_selection_get_selected(selected, &model, &iter)) {
00527         gtk_tree_model_get(model, &iter, CHAR_NAME, &name, -1);
00528 
00529         play_character(name);
00530     }
00531 }
00532 
00538 void
00539 on_button_create_character_clicked(GtkButton *button, gpointer user_data)
00540 {
00541     gtk_widget_hide(choose_char_window);
00542     if (serverloginmethod >= 2) {
00543         create_character_window_show();
00544     } else {
00545         gtk_widget_show(new_character_window);
00546         gtk_entry_set_text(GTK_ENTRY(entry_new_character_name), "");
00547     }
00548 }
00549 
00556 void
00557 on_button_add_character_clicked(GtkButton *button, gpointer user_data)
00558 {
00559     gtk_widget_hide(choose_char_window);
00560     gtk_widget_show(add_character_window);
00561     gtk_entry_set_text(GTK_ENTRY(entry_character_name), "");
00562     gtk_entry_set_text(GTK_ENTRY(entry_character_password), "");
00563     gtk_widget_grab_focus(entry_character_name);
00564 }
00565 
00572 void
00573 on_button_return_login_clicked(GtkButton *button, gpointer user_data)
00574 {
00575     gtk_widget_hide(choose_char_window);
00576     gtk_widget_show(login_window);
00577 }
00578 
00585 void
00586 on_button_account_password_clicked(GtkButton *button, gpointer user_data)
00587 {
00588     gtk_widget_hide(choose_char_window);
00589     gtk_widget_show(account_password_window);
00590     /* reset previous values */
00591     gtk_entry_set_text(GTK_ENTRY(entry_account_password_current), "");
00592     gtk_entry_set_text(GTK_ENTRY(entry_account_password_new), "");
00593     gtk_entry_set_text(GTK_ENTRY(entry_account_password_confirm), "");
00594 }
00595 
00610 void update_character_choose(const char *name, const char *class,
00611                              const char *race, const char *face,
00612                              const char *party, const char *map,
00613                              int level, int faceno)
00614 {
00615     GtkTreeIter iter;
00616 
00617     gtk_list_store_append(character_store, &iter);
00618 
00619     /* If this pixmap matches pixmap[0], it means we are caching images and
00620      * this image hasn't been set up.  It looks better in this case to just
00621      * leave that area of the window blank vs drawing a question mark there.
00622      */
00623     if (pixmaps[faceno] == pixmaps[0]) {
00624         gtk_list_store_set(character_store, &iter,
00625                        CHAR_NAME, name,
00626                        CHAR_CLASS, class,
00627                        CHAR_RACE, race,
00628                        CHAR_IMAGE, face,
00629                        CHAR_PARTY, party,
00630                        CHAR_MAP, map,
00631                        CHAR_LEVEL, level,
00632                        -1);
00633     } else {
00634         gtk_list_store_set(character_store, &iter,
00635                        CHAR_ICON, pixmaps[faceno]->icon_image,
00636                        CHAR_NAME, name,
00637                        CHAR_CLASS, class,
00638                        CHAR_RACE, race,
00639                        CHAR_IMAGE, face,
00640                        CHAR_PARTY, party,
00641                        CHAR_MAP, map,
00642                        CHAR_LEVEL, level,
00643                        -1);
00644     }
00645 }
00646 
00657 void on_treeview_choose_character_activated(GtkTreeView       *treeview,
00658                                             GtkTreePath       *path,
00659                                             GtkTreeViewColumn *column,
00660                                             gpointer          user_data)
00661 {
00662     GtkTreeIter iter;
00663     GtkTreeModel    *model;
00664     char *name;
00665 
00666     model = gtk_tree_view_get_model(treeview);
00667     if (gtk_tree_model_get_iter(model, &iter, path)) {
00668         gtk_tree_model_get(model, &iter, CHAR_NAME, &name, -1);
00669 
00670         if (!name) {
00671             LOG(LOG_ERROR,"account.c::on_treeview_choose_character_activated", "unable to get character name");
00672             return;
00673         }
00674         play_character(name);
00675     }
00676 }
00677 
00681 static void init_choose_char_window(void) {
00682 
00683     GladeXML *xml_tree;
00684     GtkTextIter end;
00685     GtkCellRenderer *renderer;
00686     GtkTreeViewColumn *column;
00687 
00688     choose_char_window =
00689         glade_xml_get_widget(dialog_xml, "choose_character_window");
00690 
00691     gtk_window_set_transient_for(
00692         GTK_WINDOW(choose_char_window), GTK_WINDOW(window_root));
00693 
00694     xml_tree = glade_get_widget_tree(GTK_WIDGET(choose_char_window));
00695 
00696     button_play_character =
00697         glade_xml_get_widget(dialog_xml,"button_play_character");
00698     button_create_character =
00699         glade_xml_get_widget(dialog_xml,"button_create_character");
00700     button_add_character =
00701         glade_xml_get_widget(dialog_xml,"button_add_character");
00702     button_return_login =
00703         glade_xml_get_widget(dialog_xml,"button_return_login");
00704     button_account_password =
00705         glade_xml_get_widget(dialog_xml,"button_account_password");
00706     login_pane[TEXTVIEW_RULES_CHAR].textview =
00707         glade_xml_get_widget(dialog_xml,"textview_rules_char");
00708 
00709     textbuf_rules_char =
00710         gtk_text_view_get_buffer(
00711             GTK_TEXT_VIEW(login_pane[TEXTVIEW_RULES_CHAR].textview));
00712 
00713     treeview_choose_character =
00714         glade_xml_get_widget(dialog_xml,"treeview_choose_character");
00715 
00716     add_tags_to_textbuffer(
00717         &login_pane[TEXTVIEW_RULES_CHAR], textbuf_rules_char);
00718     add_style_to_textbuffer(&login_pane[TEXTVIEW_RULES_CHAR], NULL);
00719     gtk_text_buffer_get_end_iter(
00720         login_pane[TEXTVIEW_RULES_CHAR].textbuffer, &end);
00721     login_pane[TEXTVIEW_RULES_CHAR].textmark =
00722         gtk_text_buffer_create_mark(
00723             login_pane[TEXTVIEW_RULES_CHAR].textbuffer, NULL, &end, FALSE);
00724 
00725     g_signal_connect((gpointer) choose_char_window, "delete_event",
00726                      G_CALLBACK(on_window_delete_event), NULL);
00727     g_signal_connect((gpointer) button_play_character, "clicked",
00728                      G_CALLBACK(on_button_play_character_clicked), NULL);
00729     g_signal_connect((gpointer) button_create_character, "clicked",
00730                      G_CALLBACK(on_button_create_character_clicked), NULL);
00731     g_signal_connect((gpointer) button_add_character, "clicked",
00732                      G_CALLBACK(on_button_add_character_clicked), NULL);
00733     g_signal_connect((gpointer) button_return_login, "clicked",
00734                      G_CALLBACK(on_button_return_login_clicked), NULL);
00735     g_signal_connect((gpointer) button_account_password, "clicked",
00736                      G_CALLBACK(on_button_account_password_clicked), NULL);
00737     g_signal_connect((gpointer) treeview_choose_character, "row_activated",
00738                      G_CALLBACK(on_treeview_choose_character_activated), NULL);
00739 
00740     character_store = gtk_list_store_new(CHAR_NUM_COLUMNS,
00741                                          G_TYPE_STRING, G_TYPE_STRING,
00742                                          G_TYPE_STRING, G_TYPE_STRING,
00743                                          G_TYPE_INT, G_TYPE_STRING,
00744                                          G_TYPE_STRING, G_TYPE_OBJECT);
00745     gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_choose_character),
00746                             GTK_TREE_MODEL(character_store));
00747 
00748     renderer = gtk_cell_renderer_pixbuf_new();
00749     column = gtk_tree_view_column_new_with_attributes("?", renderer,
00750                                                       "pixbuf", CHAR_ICON,
00751                                                       NULL);
00752 
00753     gtk_tree_view_column_set_min_width(column, image_size);
00754     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
00755 
00756     renderer = gtk_cell_renderer_text_new();
00757     column = gtk_tree_view_column_new_with_attributes("Character Name", renderer,
00758                                                       "text", CHAR_NAME, NULL);
00759     gtk_tree_view_column_set_sort_column_id(column, CHAR_NAME);
00760     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
00761 
00762     renderer = gtk_cell_renderer_text_new();
00763     column = gtk_tree_view_column_new_with_attributes("Class", renderer,
00764                                                       "text", CHAR_CLASS, NULL);
00765     gtk_tree_view_column_set_sort_column_id(column, CHAR_CLASS);
00766     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
00767 
00768     renderer = gtk_cell_renderer_text_new();
00769     column = gtk_tree_view_column_new_with_attributes("Race", renderer,
00770                                                       "text", CHAR_RACE, NULL);
00771     gtk_tree_view_column_set_sort_column_id(column, CHAR_RACE);
00772     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
00773 
00774     renderer = gtk_cell_renderer_text_new();
00775     column = gtk_tree_view_column_new_with_attributes("Level", renderer,
00776                                                       "text", CHAR_LEVEL, NULL);
00777     gtk_tree_view_column_set_sort_column_id(column, CHAR_LEVEL);
00778     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
00779 
00780     renderer = gtk_cell_renderer_text_new();
00781     column = gtk_tree_view_column_new_with_attributes("Party", renderer,
00782                                                       "text", CHAR_PARTY, NULL);
00783     gtk_tree_view_column_set_sort_column_id(column, CHAR_PARTY);
00784     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
00785 
00786     renderer = gtk_cell_renderer_text_new();
00787     column = gtk_tree_view_column_new_with_attributes("Map", renderer,
00788                                                       "text", CHAR_MAP, NULL);
00789     gtk_tree_view_column_set_sort_column_id(column, CHAR_MAP);
00790     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
00791 }
00792 
00793 /******************************************************************************
00794  * create_account_window
00795  ******************************************************************************/
00796 
00802 void account_creation_failure(char *message)
00803 {
00804     gtk_label_set_text(GTK_LABEL(label_create_account_status), message);
00805 }
00806 
00819 static void do_account_create(const char *name, const char *p1, const char *p2)
00820 {
00821     SockList sl;
00822     uint8 buf[MAX_BUF];
00823 
00824     if (strcmp(p1, p2)) {
00825         gtk_label_set_text(GTK_LABEL(label_create_account_status),
00826                       "The passwords you entered do not match!");
00827         return;
00828     } else {
00829         gtk_label_set_text(GTK_LABEL(label_create_account_status), "");
00830         SockList_Init(&sl, buf);
00831         SockList_AddString(&sl, "accountnew ");
00832         SockList_AddChar(&sl, strlen(name));
00833         SockList_AddString(&sl, name);
00834         SockList_AddChar(&sl, strlen(p1));
00835         SockList_AddString(&sl, p1);
00836         SockList_Send(&sl, csocket.fd);
00837         /* Store password away for new character creation */
00838         snprintf(account_password, sizeof(account_password), "%s", p1);
00839     }
00840 }
00841 
00848 void
00849 on_button_new_create_account_clicked(GtkButton *button, gpointer user_data)
00850 {
00851     const char *password1, *password2, *name;
00852 
00853     password1 = gtk_entry_get_text(GTK_ENTRY(entry_new_account_password));
00854     password2 = gtk_entry_get_text(GTK_ENTRY(entry_new_confirm_password));
00855     name = gtk_entry_get_text(GTK_ENTRY(entry_new_account_name));
00856 
00857     if (name && name[0] && password1 && password1[0] && password2 && password2[0]) {
00858         do_account_create(name, password1, password2);
00859     } else {
00860         gtk_label_set_text(GTK_LABEL(label_create_account_status),
00861                       "You must fill in all three entries!");
00862     }
00863 }
00864 
00870 void
00871 on_button_new_cancel_clicked(GtkButton *button, gpointer user_data)
00872 {
00873     gtk_widget_hide(create_account_window);
00874     gtk_widget_show(login_window);
00875 }
00876 
00886 void
00887 on_entry_new_account(GtkEntry *entry, gpointer user_data) {
00888 
00889     const char *password1, *password2, *name, *cp;
00890 
00891     password1 = gtk_entry_get_text(GTK_ENTRY(entry_new_account_password));
00892     password2 = gtk_entry_get_text(GTK_ENTRY(entry_new_confirm_password));
00893     name = gtk_entry_get_text(GTK_ENTRY(entry_new_account_name));
00894     if (name && name[0] && password1 && password1[0] && password2 && password2[0]) {
00895         do_account_create(name, password1, password2);
00896     } else {
00897         /* In this case, one, or more, of the fields is blank.  If there were
00898          * more than 3 widgets, I might but them into an array to make cycling
00899          * easier
00900          */
00901 
00902         /* First case - if the currently active one is blank, no reason to
00903          * move onward.
00904          */
00905         cp = gtk_entry_get_text(entry);
00906         if (!cp || !cp[0]) return;
00907 
00908         /* I'm not sure if it would make more sense to advance to the first
00909          * NULL entry - but in that case, the pointer may hop in non intuitive
00910          * ways - in this case, the user may just need to hit return a few
00911          * times - MSW 2010/03/29
00912          */
00913         if (entry == GTK_ENTRY(entry_new_account_name))
00914             gtk_widget_grab_focus(entry_new_account_password);
00915         else if (entry == GTK_ENTRY(entry_new_account_password))
00916             gtk_widget_grab_focus(entry_new_confirm_password);
00917         else if (entry == GTK_ENTRY(entry_new_confirm_password))
00918             gtk_widget_grab_focus(entry_new_account_name);
00919     }
00920 }
00921 
00926 static void init_create_account_window(void)
00927 {
00928     GladeXML *xml_tree;
00929     GtkTextIter end;
00930 
00931     create_account_window =
00932         glade_xml_get_widget(dialog_xml, "create_account_window");
00933 
00934     gtk_window_set_transient_for(
00935         GTK_WINDOW(create_account_window), GTK_WINDOW(window_root));
00936 
00937     xml_tree = glade_get_widget_tree(GTK_WIDGET(create_account_window));
00938 
00939     button_new_create_account =
00940         glade_xml_get_widget(dialog_xml,"button_new_create_account");
00941     button_new_cancel =
00942         glade_xml_get_widget(dialog_xml,"button_new_cancel");
00943     login_pane[TEXTVIEW_RULES_ACCOUNT].textview =
00944         glade_xml_get_widget(dialog_xml,"textview_rules_account");
00945 
00946     textbuf_rules_account =
00947         gtk_text_view_get_buffer(
00948             GTK_TEXT_VIEW(login_pane[TEXTVIEW_RULES_ACCOUNT].textview ));
00949 
00950     entry_new_account_name =
00951         glade_xml_get_widget(dialog_xml,"entry_new_account_name");
00952     entry_new_account_password =
00953         glade_xml_get_widget(dialog_xml,"entry_new_account_password");
00954     entry_new_confirm_password =
00955         glade_xml_get_widget(dialog_xml,"entry_new_confirm_password");
00956     label_create_account_status =
00957         glade_xml_get_widget(dialog_xml,"label_create_account_status");
00958 
00959     add_tags_to_textbuffer(
00960         &login_pane[TEXTVIEW_RULES_ACCOUNT], textbuf_rules_account);
00961     add_style_to_textbuffer(&login_pane[TEXTVIEW_RULES_ACCOUNT], NULL);
00962     gtk_text_buffer_get_end_iter(
00963         login_pane[TEXTVIEW_RULES_ACCOUNT].textbuffer, &end);
00964     login_pane[TEXTVIEW_RULES_ACCOUNT].textmark =
00965         gtk_text_buffer_create_mark(
00966             login_pane[TEXTVIEW_RULES_ACCOUNT].textbuffer, NULL, &end, FALSE);
00967 
00968     g_signal_connect((gpointer) create_account_window, "delete_event",
00969                      G_CALLBACK(on_window_delete_event), NULL);
00970     g_signal_connect((gpointer) button_new_create_account, "clicked",
00971                      G_CALLBACK(on_button_new_create_account_clicked), NULL);
00972     g_signal_connect((gpointer) button_new_cancel, "clicked",
00973                      G_CALLBACK(on_button_new_cancel_clicked), NULL);
00974     g_signal_connect((gpointer) entry_new_account_name, "activate",
00975                      G_CALLBACK(on_entry_new_account), NULL);
00976     g_signal_connect((gpointer) entry_new_account_password, "activate",
00977                      G_CALLBACK(on_entry_new_account), NULL);
00978     g_signal_connect((gpointer) entry_new_confirm_password, "activate",
00979                      G_CALLBACK(on_entry_new_account), NULL);
00980 }
00981 
00982 /*****************************************************************************
00983  * login_window
00984  *****************************************************************************/
00985 
00991 void account_login_failure(char *message)
00992 {
00993     gtk_label_set_text(GTK_LABEL(label_account_login_status), message);
00994 }
00995 
01002 void
01003 on_button_create_account_clicked(GtkButton *button, gpointer user_data)
01004 {
01005     gtk_widget_hide(login_window);
01006     gtk_label_set_text(GTK_LABEL(label_create_account_status), "");
01007     gtk_entry_set_text(GTK_ENTRY(entry_new_account_name), "");
01008     gtk_entry_set_text(GTK_ENTRY(entry_new_account_password), "");
01009     gtk_entry_set_text(GTK_ENTRY(entry_new_confirm_password), "");
01010     gtk_widget_show(create_account_window);
01011 }
01012 
01020 void
01021 on_button_go_metaserver_clicked(GtkButton *button, gpointer user_data)
01022 {
01023     close_server_connection();
01024 
01025     if (csocket_fd) {
01026         gdk_input_remove(csocket_fd);
01027         csocket_fd=0;
01028         gtk_main_quit();
01029     }
01030 }
01031 
01037 void
01038 on_button_exit_client_clicked(GtkButton *button, gpointer user_data)
01039 {
01040 #ifdef WIN32
01041     script_killall();
01042 #endif
01043     exit(0);
01044 }
01045 
01053 static void do_account_login(const char *name, const char *password)
01054 {
01055     SockList sl;
01056     uint8 buf[MAX_BUF];
01057 
01058     if (!name || !password || *name == 0 || *password == 0) {
01059         gtk_label_set_text(GTK_LABEL(label_account_login_status),
01060                       "You must enter both a name and password!");
01061     } else {
01062         gtk_label_set_text(GTK_LABEL(label_account_login_status), "");
01063 
01064         SockList_Init(&sl, buf);
01065         SockList_AddString(&sl, "accountlogin ");
01066         SockList_AddChar(&sl, strlen(name));
01067         SockList_AddString(&sl, name);
01068         SockList_AddChar(&sl, strlen(password));
01069         SockList_AddString(&sl, password);
01070         SockList_Send(&sl, csocket.fd);
01071         /* Store password away for new character creation */
01072         snprintf(account_password, sizeof(account_password), "%s", password);
01073     }
01074 }
01075 
01081 void
01082 on_button_login_clicked(GtkButton *button, gpointer user_data)
01083 {
01084     do_account_login(gtk_entry_get_text(GTK_ENTRY(entry_account_name)),
01085                      gtk_entry_get_text(GTK_ENTRY(entry_account_password)));
01086 }
01087 
01094 void
01095 on_entry_account_name_activate(GtkEntry *entry, gpointer user_data) {
01096     const char *password;
01097 
01098     password = gtk_entry_get_text(GTK_ENTRY(entry_account_password));
01099 
01100     if (!password || *password == 0) {
01101         gtk_widget_grab_focus(entry_account_password);
01102     } else {
01103         do_account_login(gtk_entry_get_text(GTK_ENTRY(entry_account_name)), password);
01104     }
01105 }
01106 
01113 void
01114 on_entry_account_password_activate(GtkEntry *entry, gpointer user_data) {
01115     const char *name;
01116 
01117     name = gtk_entry_get_text(GTK_ENTRY(entry_account_name));
01118 
01119     if (!name || *name == 0) {
01120         gtk_widget_grab_focus(entry_account_name);
01121     } else {
01122         do_account_login(name, gtk_entry_get_text(GTK_ENTRY(entry_account_password)));
01123     }
01124 }
01125 
01130 static void init_login_window(void)
01131 {
01132     GladeXML *xml_tree;
01133     GtkTextIter end;
01134 
01135     login_window = glade_xml_get_widget(dialog_xml, "login_window");
01136 
01137     if (!login_window) {
01138         error_dialog("Out of date dialog.glade", "Did you run 'make install'?");
01139         exit(1);
01140     }
01141 
01142     gtk_window_set_transient_for(
01143         GTK_WINDOW(login_window), GTK_WINDOW(window_root));
01144 
01145     xml_tree = glade_get_widget_tree(GTK_WIDGET(login_window));
01146 
01147     button_login =
01148         glade_xml_get_widget(dialog_xml,"button_login");
01149     button_create_account =
01150         glade_xml_get_widget(dialog_xml,"button_create_account");
01151     button_go_metaserver =
01152         glade_xml_get_widget(dialog_xml,"button_go_metaserver");
01153     button_exit_client =
01154         glade_xml_get_widget(dialog_xml,"button_exit_client");
01155     label_account_login_status =
01156         glade_xml_get_widget(dialog_xml,"label_account_login_status");
01157     login_pane[TEXTVIEW_MOTD].textview =
01158         glade_xml_get_widget(dialog_xml,"textview_motd");
01159 
01160     textbuf_motd =
01161         gtk_text_view_get_buffer(
01162             GTK_TEXT_VIEW(login_pane[TEXTVIEW_MOTD].textview));
01163 
01164     add_tags_to_textbuffer(&login_pane[TEXTVIEW_MOTD], textbuf_motd);
01165     add_style_to_textbuffer(&login_pane[TEXTVIEW_MOTD], NULL);
01166     gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_MOTD].textbuffer, &end);
01167     login_pane[TEXTVIEW_MOTD].textmark =
01168         gtk_text_buffer_create_mark(
01169             login_pane[TEXTVIEW_MOTD].textbuffer, NULL, &end, FALSE);
01170 
01171     login_pane[TEXTVIEW_NEWS].textview =
01172         glade_xml_get_widget(dialog_xml,"textview_news");
01173 
01174     textbuf_news =
01175         gtk_text_view_get_buffer(
01176             GTK_TEXT_VIEW(login_pane[TEXTVIEW_NEWS].textview));
01177 
01178     add_tags_to_textbuffer(&login_pane[TEXTVIEW_NEWS], textbuf_news);
01179     add_style_to_textbuffer(&login_pane[TEXTVIEW_NEWS], NULL);
01180     gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_NEWS].textbuffer, &end);
01181     login_pane[TEXTVIEW_NEWS].textmark =
01182         gtk_text_buffer_create_mark(
01183             login_pane[TEXTVIEW_NEWS].textbuffer, NULL, &end, FALSE);
01184 
01185     entry_account_name =
01186         glade_xml_get_widget(dialog_xml,"entry_account_name");
01187     entry_account_password =
01188         glade_xml_get_widget(dialog_xml,"entry_account_password");
01189 
01190     g_signal_connect((gpointer) login_window, "delete_event",
01191                      G_CALLBACK(on_window_delete_event), NULL);
01192     g_signal_connect((gpointer) entry_account_name, "activate",
01193                      G_CALLBACK(on_entry_account_name_activate), NULL);
01194     g_signal_connect((gpointer) entry_account_password, "activate",
01195                      G_CALLBACK(on_entry_account_password_activate), NULL);
01196     g_signal_connect((gpointer) button_login, "clicked",
01197                      G_CALLBACK(on_button_login_clicked), NULL);
01198     g_signal_connect((gpointer) button_create_account, "clicked",
01199                      G_CALLBACK(on_button_create_account_clicked), NULL);
01200     g_signal_connect((gpointer) button_go_metaserver, "clicked",
01201                      G_CALLBACK(on_button_go_metaserver_clicked), NULL);
01202     g_signal_connect((gpointer) button_exit_client, "clicked",
01203                      G_CALLBACK(on_button_exit_client_clicked), NULL);
01204 }
01205 
01206 /*****************************************************************************
01207  * Account password change
01208  ****************************************************************************/
01209 
01222 static void do_account_change(const char *old, const char *p1, const char *p2)
01223 {
01224     SockList sl;
01225     uint8 buf[MAX_BUF];
01226 
01227     if (strcmp(p1, p2)) {
01228         gtk_label_set_text(GTK_LABEL(label_account_password_status),
01229                       "The passwords you entered do not match!");
01230         return;
01231     } else {
01232         gtk_label_set_text(GTK_LABEL(label_account_password_status), "");
01233         SockList_Init(&sl, buf);
01234         SockList_AddString(&sl, "accountpw ");
01235         SockList_AddChar(&sl, strlen(old));
01236         SockList_AddString(&sl, old);
01237         SockList_AddChar(&sl, strlen(p1));
01238         SockList_AddString(&sl, p1);
01239         SockList_Send(&sl, csocket.fd);
01240         /* Store password away for new character creation */
01241         snprintf(account_password, sizeof(account_password), "%s", p1);
01242     }
01243 }
01244 
01251 void
01252 on_button_account_password_cancel_clicked(GtkButton *button, gpointer user_data)
01253 {
01254     gtk_widget_hide(account_password_window);
01255     gtk_widget_show(choose_char_window);
01256 }
01257 
01263 void
01264 on_button_account_password_confirm_clicked(GtkButton *button, gpointer user_data)
01265 {
01266     do_account_change(gtk_entry_get_text(GTK_ENTRY(entry_account_password_current)),
01267         gtk_entry_get_text(GTK_ENTRY(entry_account_password_new)),
01268         gtk_entry_get_text(GTK_ENTRY(entry_account_password_confirm)));
01269 }
01270 
01280 void
01281 on_entry_account_password(GtkEntry *entry, gpointer user_data) {
01282 
01283     const char *old, *password1, *password2, *cp;
01284 
01285     old = gtk_entry_get_text(GTK_ENTRY(entry_account_password_current));
01286     password1 = gtk_entry_get_text(GTK_ENTRY(entry_account_password_new));
01287     password2 = gtk_entry_get_text(GTK_ENTRY(entry_account_password_confirm));
01288     if (old && old[0] && password1 && password1[0] && password2 && password2[0]) {
01289         do_account_change(old, password1, password2);
01290     } else {
01291         /* In this case, one, or more, of the fields is blank.  If there were
01292          * more than 3 widgets, I might but them into an array to make cycling
01293          * easier
01294          */
01295 
01296         /* First case - if the currently active one is blank, no reason to
01297          * move onward.
01298          */
01299         cp = gtk_entry_get_text(entry);
01300         if (!cp || !cp[0]) return;
01301 
01302         if (entry == GTK_ENTRY(entry_account_password_current))
01303             gtk_widget_grab_focus(entry_account_password_new);
01304         else if (entry == GTK_ENTRY(entry_account_password_new))
01305             gtk_widget_grab_focus(entry_account_password_confirm);
01306         else if (entry == GTK_ENTRY(entry_account_password_confirm))
01307             gtk_widget_grab_focus(entry_account_password_current);
01308     }
01309 }
01310 
01311 void account_change_password_failure(char *message) {
01312     gtk_label_set_text(GTK_LABEL(label_account_password_status), message);
01313 }
01314 
01319 static void init_account_password_window(void)
01320 {
01321     GladeXML *xml_tree;
01322     GtkTextIter end;
01323 
01324     account_password_window =
01325         glade_xml_get_widget(dialog_xml, "account_password_window");
01326 
01327     gtk_window_set_transient_for(
01328         GTK_WINDOW(account_password_window), GTK_WINDOW(window_root));
01329 
01330     xml_tree = glade_get_widget_tree(GTK_WIDGET(account_password_window));
01331 
01332     button_account_password_confirm =
01333         glade_xml_get_widget(dialog_xml,"button_account_password_confirm");
01334     button_account_password_cancel =
01335         glade_xml_get_widget(dialog_xml,"button_account_password_cancel");
01336 
01337     entry_account_password_current =
01338         glade_xml_get_widget(dialog_xml,"entry_account_password_current");
01339     entry_account_password_new =
01340         glade_xml_get_widget(dialog_xml,"entry_account_password_new");
01341     entry_account_password_confirm =
01342         glade_xml_get_widget(dialog_xml,"entry_account_password_confirm");
01343     label_account_password_status =
01344         glade_xml_get_widget(dialog_xml,"label_account_password_status");
01345 
01346     g_signal_connect((gpointer) account_password_window, "delete_event",
01347                      G_CALLBACK(on_window_delete_event), NULL);
01348     g_signal_connect((gpointer) button_account_password_confirm, "clicked",
01349                      G_CALLBACK(on_button_account_password_confirm_clicked), NULL);
01350     g_signal_connect((gpointer) button_account_password_cancel, "clicked",
01351                      G_CALLBACK(on_button_account_password_cancel_clicked), NULL);
01352     g_signal_connect((gpointer) entry_account_password_current, "activate",
01353                      G_CALLBACK(on_entry_account_password), NULL);
01354     g_signal_connect((gpointer) entry_account_password_new, "activate",
01355                      G_CALLBACK(on_entry_account_password), NULL);
01356     g_signal_connect((gpointer) entry_account_password_confirm, "activate",
01357                      G_CALLBACK(on_entry_account_password), NULL);
01358 }
01359 
01360 
01361 /*****************************************************************************
01362  * Common/generic functions
01363  ****************************************************************************/
01364 
01372 void update_login_info(int type)
01373 {
01374     if (!has_init) return;
01375 
01376     /* In all cases, we clear the buffer, and if we have data, then set it to
01377      * that data.  This routine could be smarter an
01378      */
01379     if (type == INFO_NEWS) {
01380         gtk_text_buffer_set_text(textbuf_news, "", 0);
01381         if (news) {
01382             /* the format of the news entry is special - there are a series of
01383              * %entries, and they are in reverse older (newest last) we want
01384              * to get rid of the %, make them more visible (convert them to
01385              * bold) and reverse the order.
01386              */
01387             char *mynews, *cp, *el, big_buf[BIG_BUF], *cp1;
01388 
01389             mynews = strdup(news);
01390             /* We basically work from the end of the string going towards the
01391              * start looking for % characters.  If we find one, we have to
01392              * make sure it is at the start of the line or start of the buffer
01393              */
01394             for (cp = mynews + strlen(mynews); cp > mynews; cp--) {
01395                 if (*cp == '%' && (*(cp-1) == '\n' || cp == mynews)) {
01396                     /* Find the end of the line */
01397                     el = strchr(cp, '\n');
01398                     /* null out the newline, put el one char beyond it */
01399                     if (el) {
01400                         *el=0;
01401                         el++;
01402                     }
01403                     /* There isn't a clear standard - % news may be valid, as
01404                      * might be %news.  If % news is used, it looks better to
01405                      * get rid of that leading space.
01406                      */
01407                     cp1 = cp+1;
01408                     while (isspace(*cp1)) cp1++;
01409 
01410                     /* since we've null out the newline, this snprintf will
01411                      * only get the % line and that is it.  Mark it up
01412                      */
01413                     snprintf(big_buf, BIG_BUF, "[b]%s[/b]", cp1);
01414                     add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], big_buf, 0, 0, 0);
01415                     /* Now we draw the text that goes with it, if it exists */
01416                     if (el)
01417                         add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], el, 0, 0, 0);
01418 
01419                     /* Now we wipe the % out.  In this way, the news buffer is
01420                      * shorter, so when it draws the ext, there will just be
01421                      * that between the % and the one we just wiped out.
01422                      */
01423                     *cp = 0;
01424                 }
01425             }
01426             /* If there are remnants left over, or perhaps the news file isn't
01427              * formatted with % headers, display what we have got.
01428              */
01429             if (*mynews != 0)
01430                 add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], mynews, 0, 0, 0);
01431         }
01432     }
01433     else if (type == INFO_MOTD) {
01434         gtk_text_buffer_set_text(textbuf_motd, "", 0);
01435         if (motd)
01436             add_marked_text_to_pane(&login_pane[TEXTVIEW_MOTD], motd, 0, 0, 0);
01437     }
01438     else if (type == INFO_RULES) {
01439         gtk_text_buffer_set_text(textbuf_rules_account, "", 0);
01440         gtk_text_buffer_set_text(textbuf_rules_char, "", 0);
01441 
01442         if (rules) {
01443             add_marked_text_to_pane(&login_pane[TEXTVIEW_RULES_ACCOUNT], rules, 0, 0, 0);
01444             add_marked_text_to_pane(&login_pane[TEXTVIEW_RULES_CHAR], rules, 0, 0, 0);
01445         }
01446     }
01447 }
01448 
01457 void start_login(int method)
01458 {
01459     /* Store this away - if method is only 1, we can not do smart character
01460      * creation.
01461      */
01462     serverloginmethod = method;
01463 
01464     if (!has_init) {
01465         /* Since there are 4 windows associated with account and character
01466          * login, to make life a little easier, each section here does all the
01467          * work for one window, so it is easier to see that everything for a
01468          * window is done - don't need to hunt through what would otherwise be
01469          * a long routine looking for entries.
01470          */
01471         init_login_window();
01472 
01473         init_add_character_window();
01474 
01475         init_choose_char_window();
01476 
01477         init_create_account_window();
01478 
01479         init_new_character_window();
01480 
01481         init_account_password_window();
01482 
01483         has_init=1;
01484 
01485         /* In case we have gotten news/motd/rules before getting here, update
01486          * it now.
01487          */
01488         update_login_info(INFO_NEWS);
01489         update_login_info(INFO_RULES);
01490         update_login_info(INFO_MOTD);
01491     }
01492 
01493     gtk_entry_set_text(GTK_ENTRY(entry_account_name), "");
01494     gtk_entry_set_text(GTK_ENTRY(entry_account_password), "");
01495     /* We set focus to account name - this makes the most sense if user is
01496      * logging in again - it is possible that the password is active, but both
01497      * fields are blank, which is not what is expected.
01498      */
01499     gtk_widget_grab_focus(entry_account_name);
01500     gtk_widget_show(login_window);
01501 }
01502