1
const char * const rcsid_gtk2_account_c =
2
"$Id: account.c 12949 2010-04-25 07:07:43Z mwedel $";
4
Crossfire client, a client program for the crossfire program.
6
Copyright (C) 2010 Mark Wedel & Crossfire Development Team
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program; if not, write to the Free Software
20
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
The author can be reached via e-mail to crossfire@metalforge.org
26
* @file gtk-v2/src/account.c
27
* Handles account login, creation, and character selection.
35
#include <glade/glade.h>
43
#include "gtk2proto.h"
44
#include "metaserver.h"
46
static GtkWidget *add_character_window, *choose_char_window,
47
*create_account_window, *login_window;
49
/* These are in the login_window */
50
static GtkWidget *button_login, *button_create_account,
51
*button_go_metaserver, *button_exit_client,
53
*entry_account_password, *label_account_login_status;
55
/* These are in the create_account_window */
56
static GtkWidget *button_new_create_account, *button_new_cancel,
57
*entry_new_account_name,
58
*entry_new_account_password, *entry_new_confirm_password,
59
*label_create_account_status;
61
/* These are in the choose_character window */
62
static GtkWidget *button_play_character, *button_create_character,
63
*button_add_character, *button_return_login,
64
*treeview_choose_character;
66
/* These are in the new_character window */
67
static GtkWidget *entry_new_character_name, *new_character_window,
68
*label_new_char_status, *button_create_new_char,
69
*button_new_char_cancel;
71
GtkListStore *character_store;
73
static char account_password[256];
75
/* This enum just maps the columns in the list store to their
78
enum {CHAR_IMAGE, CHAR_NAME, CHAR_CLASS, CHAR_RACE, CHAR_LEVEL, CHAR_PARTY,
80
#define CHAR_NUM_COLUMNS 8
82
/* These are in the add_character window */
83
static GtkWidget *button_do_add_character,
84
*button_return_character_select, *entry_character_name,
85
*entry_character_password, *label_add_status;
87
GtkTextBuffer *textbuf_motd, *textbuf_news, *textbuf_rules_account,
90
/* These are used as offsets for num_text_views -
91
* we share the drawing code in info.c
92
* if more textviews are added, note that NUM_TEXT_VIEWS
93
* in info.c needs to be increased.
95
#define TEXTVIEW_MOTD 0
96
#define TEXTVIEW_NEWS 1
97
#define TEXTVIEW_RULES_ACCOUNT 2
98
#define TEXTVIEW_RULES_CHAR 3
100
Info_Pane login_pane[4];
102
extern int num_text_views;
105
static int has_init=0;
109
* As the name implies, this hides all the login related
110
* windows. This is needed in case the client loses the connection
111
* to the server (either through player going to client/disconnect
112
* or network failure). get_metaserver() calls this, as well
115
void hide_all_login_windows()
117
extern GtkWidget *treeview_look;
120
/* If we have not initialized, nothing to hide */
121
gtk_widget_hide(login_window);
122
gtk_widget_hide(add_character_window);
123
gtk_widget_hide(choose_char_window);
124
gtk_widget_hide(create_account_window);
125
gtk_widget_hide(new_character_window);
127
/* if the player has started playing (this function being
128
* called from AddMeSuccess), we want to make sure that
129
* the extended command entry widget is not activated -
130
* we want normal command entry. Where this shows up
131
* is if the player was playing before and uses a
132
* savebed - now the last thing activated is that
135
gtk_widget_grab_focus (GTK_WIDGET(treeview_look));
140
/*****************************************************************************
141
* New character window functions
142
*****************************************************************************/
144
void create_new_character_failure(char *message)
146
gtk_label_set_text(GTK_LABEL(label_new_char_status),
150
static void create_new_character()
156
SockList_Init(&sl, buf);
158
name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
160
if (!name || *name == 0) {
161
gtk_label_set_text(GTK_LABEL(label_new_char_status),
162
"You must enter a character name.");
165
gtk_label_set_text(GTK_LABEL(label_new_char_status),
168
SockList_AddString(&sl, "createplayer ");
169
SockList_AddChar(&sl, strlen(name));
170
SockList_AddString(&sl, name);
171
SockList_AddChar(&sl, strlen(account_password));
172
SockList_AddString(&sl, account_password);
173
SockList_Send(&sl, csocket.fd);
179
* User hit the create character button. Get data, send to server.
182
on_button_create_new_char_clicked (GtkButton *button, gpointer user_data)
184
create_new_character();
188
* User hit return in the new character name box. Like above,
189
* get data and send to server.
191
void on_entry_new_character_name(GtkEntry *entry, gpointer user_data)
193
create_new_character();
197
* User his hit the cancel button in the new character window.
198
* hide the new character window, show the choose character window.
201
on_button_new_char_cancel_clicked(GtkButton *button, gpointer user_data)
203
gtk_widget_hide(new_character_window);
204
gtk_widget_show(choose_char_window);
210
* Initializes the new character window.
212
static void init_new_character_window()
216
new_character_window = glade_xml_get_widget(dialog_xml, "new_character_window");
217
gtk_window_set_transient_for(GTK_WINDOW(new_character_window), GTK_WINDOW(window_root));
219
xml_tree = glade_get_widget_tree(GTK_WIDGET(new_character_window));
221
button_create_new_char = glade_xml_get_widget(dialog_xml,"button_create_new_char");
222
button_new_char_cancel =
223
glade_xml_get_widget(dialog_xml,"button_new_char_cancel");
224
entry_new_character_name = glade_xml_get_widget(dialog_xml,"entry_new_character_name");
225
label_new_char_status = glade_xml_get_widget(dialog_xml,"label_new_char_status");
227
g_signal_connect ((gpointer) button_create_new_char, "clicked",
228
G_CALLBACK (on_button_create_new_char_clicked), NULL);
229
g_signal_connect ((gpointer) button_new_char_cancel, "clicked",
230
G_CALLBACK (on_button_new_char_cancel_clicked), NULL);
231
g_signal_connect ((gpointer) entry_new_character_name, "activate",
232
G_CALLBACK (on_entry_new_character_name), NULL);
236
/******************************************************************************
237
* add_character_window functions
238
*****************************************************************************/
241
* This just sends a request to the server add add the
242
* character to this account.
244
static void add_character_to_account(const char *name, const char *password, int force)
249
if (!name || !password || *name == 0 || *password == 0) {
250
gtk_label_set_text(GTK_LABEL(label_add_status),
251
"You must enter both a name and password!");
253
gtk_label_set_text(GTK_LABEL(label_add_status), "");
255
SockList_Init(&sl, buf);
256
SockList_AddString(&sl, "accountaddplayer ");
257
SockList_AddChar(&sl, force);
258
SockList_AddChar(&sl, strlen(name));
259
SockList_AddString(&sl, name);
260
SockList_AddChar(&sl, strlen(password));
261
SockList_AddString(&sl, password);
262
SockList_Send(&sl, csocket.fd);
268
* handles a failure from the server - pretty basic - just
269
* throw up the message and let the user try again.
270
* This is a response to the 'failure accountaddplayer' command.
271
* Calling this account_add_character_failure may be a little
272
* bit of a misnomer, but all the other routines in this area refer
273
* to character, not player.
276
* message to display. Unlike other messages, the first
277
* word of this message should be an integer, which denotes
278
* if using the 'force' option would allow the user
281
void account_add_character_failure(char *message)
286
retry = atoi(message);
287
cp = strchr(message,' ');
294
gtk_label_set_text(GTK_LABEL(label_add_status), cp);
296
/* In this case, we can retry it and it should work
298
* So bring up a dialog, as the user what to do -
299
* if they enter yes, we use force. If not,
300
* we clear the entry fields and just continue
305
const char *name, *password;
307
/* Bring up a dialog window */
309
gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
310
GTK_BUTTONS_YES_NO, "%s\n%s", cp, "Apply anyways?");
311
result = gtk_dialog_run(GTK_DIALOG(dialog));
312
gtk_widget_destroy(dialog);
314
if (result == GTK_RESPONSE_YES ) {
315
name = gtk_entry_get_text(GTK_ENTRY(entry_character_name));
316
password = gtk_entry_get_text(GTK_ENTRY(entry_character_password));
317
add_character_to_account(name, password, 1);
319
gtk_entry_set_text(GTK_ENTRY(entry_character_name), "");
320
gtk_entry_set_text(GTK_ENTRY(entry_character_password), "");
321
gtk_widget_grab_focus(entry_character_name);
327
* User has hit the add character button. Let add_character_to_account()
333
on_button_do_add_character_clicked (GtkButton *button, gpointer user_data)
335
add_character_to_account(gtk_entry_get_text(GTK_ENTRY(entry_character_name)),
336
gtk_entry_get_text(GTK_ENTRY(entry_character_password)), 0);
342
* User has hit the return to character selection button. Pretty simple -
343
* just hide this window, activate the other window.
348
on_button_return_character_select_clicked (GtkButton *button, gpointer user_data)
350
gtk_widget_hide(add_character_window);
351
gtk_widget_show(choose_char_window);
355
* User has hit return in either name or password box. If both
356
* boxes have non empty data, process request. Otherwise,
357
* either stay in same box if this box is empty, or move
361
* Entry widget which generated this callback.
363
void on_entry_character(GtkEntry *entry, gpointer user_data) {
364
const char *name, *password;
366
name = gtk_entry_get_text(GTK_ENTRY(entry_character_name));
367
password = gtk_entry_get_text(GTK_ENTRY(entry_character_password));
369
if (name && name[0] && password && password[0]) {
370
add_character_to_account(name, password, 0);
374
/* First case - this widget is empty - do nothing */
375
cp = gtk_entry_get_text(entry);
376
if (!cp || !cp[0]) return;
378
/* In this case, this widget is not empty - means the
381
if (entry == GTK_ENTRY(entry_character_name))
382
gtk_widget_grab_focus(entry_character_password);
384
gtk_widget_grab_focus(entry_character_name);
390
static void init_add_character_window() {
393
add_character_window = glade_xml_get_widget(dialog_xml, "add_character_window");
394
gtk_window_set_transient_for(GTK_WINDOW(add_character_window), GTK_WINDOW(window_root));
396
xml_tree = glade_get_widget_tree(GTK_WIDGET(add_character_window));
397
button_do_add_character = glade_xml_get_widget(dialog_xml,"button_do_add_character");
398
button_return_character_select =
399
glade_xml_get_widget(dialog_xml,"button_return_character_select");
400
entry_character_name = glade_xml_get_widget(dialog_xml,"entry_character_name");
401
entry_character_password = glade_xml_get_widget(dialog_xml,"entry_character_password");
402
label_add_status = glade_xml_get_widget(dialog_xml,"label_add_status");
404
g_signal_connect ((gpointer) button_do_add_character, "clicked",
405
G_CALLBACK (on_button_do_add_character_clicked), NULL);
407
g_signal_connect ((gpointer) button_return_character_select, "clicked",
408
G_CALLBACK (on_button_return_character_select_clicked), NULL);
409
g_signal_connect ((gpointer) entry_character_name, "activate",
410
G_CALLBACK (on_entry_character), NULL);
411
g_signal_connect ((gpointer) entry_character_password, "activate",
412
G_CALLBACK (on_entry_character), NULL);
415
/*****************************************************************************
417
****************************************************************************/
420
* this is called when we get the accountplayers command from
421
* the server (indirectly via AccountPlayersCmd). This tells
422
* us to wipe any data from the treeview, but also hide
423
* any other windows and make the choose_character_window
426
void choose_character_init()
428
gtk_widget_hide(login_window);
429
gtk_widget_hide(add_character_window);
430
gtk_widget_hide(create_account_window);
431
gtk_widget_show(choose_char_window);
433
/* Store any old/stale entries */
434
gtk_list_store_clear(character_store);
438
* User has done necessary steps to play a
441
static void play_character(const char *name)
446
SockList_Init(&sl, buf);
447
SockList_AddString(&sl, "accountplay ");
448
SockList_AddString(&sl, name);
449
SockList_Send(&sl, csocket.fd);
453
* User has hit the play character button. Grab
454
* the selected entry, if there is one.
457
on_button_play_character_clicked (GtkButton *button, gpointer user_data)
459
GtkTreeSelection *selected;
464
selected = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_choose_character));
466
if (gtk_tree_selection_get_selected (selected, &model, &iter)) {
467
gtk_tree_model_get(model, &iter, CHAR_NAME, &name, -1);
469
play_character(name);
474
on_button_create_character_clicked (GtkButton *button, gpointer user_data)
476
gtk_widget_hide(choose_char_window);
477
gtk_widget_show(new_character_window);
478
gtk_entry_set_text(GTK_ENTRY(entry_new_character_name), "");
482
* User has hit the add character button.
483
* hide this window, show the add character window.
486
on_button_add_character_clicked (GtkButton *button, gpointer user_data)
488
gtk_widget_hide(choose_char_window);
489
gtk_widget_show(add_character_window);
490
gtk_entry_set_text(GTK_ENTRY(entry_character_name), "");
491
gtk_entry_set_text(GTK_ENTRY(entry_character_password), "");
492
gtk_widget_grab_focus(entry_character_name);
496
* User has hit the return to login window.
497
* hide this window, show the account login window.
500
on_button_return_login_clicked(GtkButton *button, gpointer user_data)
502
gtk_widget_hide(choose_char_window);
503
gtk_widget_show(login_window);
507
* This gets data and adds it to the list store. This is called
508
* from AccountPlayersCmd and data is from the accountplayers protocol
512
* data to add to the list store.
514
void update_character_choose(const char *name, const char *class,
515
const char *race, const char *face,
516
const char *party, const char *map,
517
int level, int faceno)
521
gtk_list_store_append(character_store, &iter);
523
/* If this pixmap matches pixmap[0], it means we are caching images
524
* and this image hasn't been set up. It looks better in this case
525
* to just leave that area of the window blank vs drawing
526
* a question mark there.
528
if (pixmaps[faceno] == pixmaps[0]) {
529
gtk_list_store_set(character_store, &iter,
539
gtk_list_store_set(character_store, &iter,
540
CHAR_ICON, pixmaps[faceno]->icon_image,
555
* User has double clicked one of the character rows,
556
* so use that character as the one to play.
559
* treeview which activated that (should always be treeview_choose_character)
561
* mechanism to get to selected entry
567
void on_treeview_choose_character_activated(GtkTreeView *treeview,
569
GtkTreeViewColumn *column,
576
model = gtk_tree_view_get_model(treeview);
577
if (gtk_tree_model_get_iter(model, &iter, path)) {
578
gtk_tree_model_get(model, &iter, CHAR_NAME, &name, -1);
581
LOG(LOG_ERROR,"account.c:on_treeview_choose_character_activated", "unable to get character name");
584
play_character(name);
590
static void init_choose_char_window()
594
GtkCellRenderer *renderer;
595
GtkTreeViewColumn *column;
597
choose_char_window = glade_xml_get_widget(dialog_xml, "choose_character_window");
598
gtk_window_set_transient_for(GTK_WINDOW(choose_char_window), GTK_WINDOW(window_root));
600
xml_tree = glade_get_widget_tree(GTK_WIDGET(choose_char_window));
601
button_play_character = glade_xml_get_widget(dialog_xml,"button_play_character");
602
button_create_character = glade_xml_get_widget(dialog_xml,"button_create_character");
603
button_add_character = glade_xml_get_widget(dialog_xml,"button_add_character");
604
button_return_login = glade_xml_get_widget(dialog_xml,"button_return_login");
605
login_pane[TEXTVIEW_RULES_CHAR].textview =
606
glade_xml_get_widget(dialog_xml,"textview_rules_char");
607
textbuf_rules_char = gtk_text_view_get_buffer(GTK_TEXT_VIEW(login_pane[TEXTVIEW_RULES_CHAR].textview));
608
treeview_choose_character = glade_xml_get_widget(dialog_xml,"treeview_choose_character");
610
add_tags_to_textbuffer(&login_pane[TEXTVIEW_RULES_CHAR], textbuf_rules_char);
611
add_style_to_textbuffer(&login_pane[TEXTVIEW_RULES_CHAR], NULL);
612
gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_RULES_CHAR].textbuffer, &end);
613
login_pane[TEXTVIEW_RULES_CHAR].textmark = gtk_text_buffer_create_mark(
614
login_pane[TEXTVIEW_RULES_CHAR].textbuffer, NULL, &end, FALSE);
616
g_signal_connect ((gpointer) button_play_character, "clicked",
617
G_CALLBACK (on_button_play_character_clicked), NULL);
618
g_signal_connect ((gpointer) button_create_character, "clicked",
619
G_CALLBACK (on_button_create_character_clicked), NULL);
620
g_signal_connect ((gpointer) button_add_character, "clicked",
621
G_CALLBACK (on_button_add_character_clicked), NULL);
622
g_signal_connect ((gpointer) button_return_login, "clicked",
623
G_CALLBACK (on_button_return_login_clicked), NULL);
624
g_signal_connect ((gpointer) treeview_choose_character, "row_activated",
625
G_CALLBACK (on_treeview_choose_character_activated), NULL);
627
character_store = gtk_list_store_new(CHAR_NUM_COLUMNS,
628
G_TYPE_STRING, G_TYPE_STRING,
629
G_TYPE_STRING, G_TYPE_STRING,
630
G_TYPE_INT, G_TYPE_STRING,
631
G_TYPE_STRING, G_TYPE_OBJECT);
632
gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_choose_character),
633
GTK_TREE_MODEL(character_store));
635
renderer = gtk_cell_renderer_pixbuf_new();
636
column = gtk_tree_view_column_new_with_attributes ("?", renderer,
640
gtk_tree_view_column_set_min_width(column, image_size);
641
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
643
renderer = gtk_cell_renderer_text_new();
644
column = gtk_tree_view_column_new_with_attributes ("Character Name", renderer,
645
"text", CHAR_NAME, NULL);
646
gtk_tree_view_column_set_sort_column_id(column, CHAR_NAME);
647
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
649
renderer = gtk_cell_renderer_text_new();
650
column = gtk_tree_view_column_new_with_attributes ("Class", renderer,
651
"text", CHAR_CLASS, NULL);
652
gtk_tree_view_column_set_sort_column_id(column, CHAR_CLASS);
653
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
655
renderer = gtk_cell_renderer_text_new();
656
column = gtk_tree_view_column_new_with_attributes ("Race", renderer,
657
"text", CHAR_RACE, NULL);
658
gtk_tree_view_column_set_sort_column_id(column, CHAR_RACE);
659
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
661
renderer = gtk_cell_renderer_text_new();
662
column = gtk_tree_view_column_new_with_attributes ("Level", renderer,
663
"text", CHAR_LEVEL, NULL);
664
gtk_tree_view_column_set_sort_column_id(column, CHAR_LEVEL);
665
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
667
renderer = gtk_cell_renderer_text_new();
668
column = gtk_tree_view_column_new_with_attributes ("Party", renderer,
669
"text", CHAR_PARTY, NULL);
670
gtk_tree_view_column_set_sort_column_id(column, CHAR_PARTY);
671
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
673
renderer = gtk_cell_renderer_text_new();
674
column = gtk_tree_view_column_new_with_attributes ("Map", renderer,
675
"text", CHAR_MAP, NULL);
676
gtk_tree_view_column_set_sort_column_id(column, CHAR_MAP);
677
gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
681
/******************************************************************************
682
* create_account_window
683
******************************************************************************/
686
* handles a failure from the server - pretty basic - just
687
* throw up the message and let the user try again.
689
void account_creation_failure(char *message)
691
gtk_label_set_text(GTK_LABEL(label_create_account_status), message);
695
* This does sanity checking of the passed in data, and if all
696
* is good, sends the request to the server to create an account.
697
* If all the data isn't good, it puts up an error message. In
698
* this routine, none of the entries should be NULL - the caller
699
* should verify that before callin do_account_create();
702
* desired account name - must not be NULL.
704
* the first password - must not be NULL
706
* the second (confirmed) password. This routine checks that p1 & p2
707
* are the same, and if not, puts up an error. p2 must not be NULL
709
static void do_account_create(const char *name, const char *p1, const char *p2)
714
if (strcmp(p1, p2)) {
715
gtk_label_set_text(GTK_LABEL(label_create_account_status),
716
"The passwords you entered do not match!");
719
gtk_label_set_text(GTK_LABEL(label_create_account_status),
721
SockList_Init(&sl, buf);
722
SockList_AddString(&sl, "accountnew ");
723
SockList_AddChar(&sl, strlen(name));
724
SockList_AddString(&sl, name);
725
SockList_AddChar(&sl, strlen(p1));
726
SockList_AddString(&sl, p1);
727
SockList_Send(&sl, csocket.fd);
728
/* Store password away for new character creation */
729
snprintf(account_password, 256, p1);
734
* User clicked on the create account button. In this case,
735
* we just process the data and call do_account_create();
738
on_button_new_create_account_clicked (GtkButton *button, gpointer user_data)
740
const char *password1, *password2, *name;
742
password1 = gtk_entry_get_text(GTK_ENTRY(entry_new_account_password));
743
password2 = gtk_entry_get_text(GTK_ENTRY(entry_new_confirm_password));
744
name = gtk_entry_get_text(GTK_ENTRY(entry_new_account_name));
746
if (name && name[0] && password1 && password1[0] && password2 && password2[0]) {
747
do_account_create(name, password1, password2);
749
gtk_label_set_text(GTK_LABEL(label_create_account_status),
750
"You must fill in all three entries!");
755
on_button_new_cancel_clicked (GtkButton *button, gpointer user_data)
757
gtk_widget_hide(create_account_window);
758
gtk_widget_show(login_window);
762
* This handles cases where the user hits return in
763
* one of the entry boxes. We use the same callback for
764
* all 3 entry boxes, since the processing is basically
765
* the same - if there is valid data in all of them,
766
* we try to create an account - otherwise, we move
770
* entry box - we use this to figure out what the next box is.
775
on_entry_new_account (GtkEntry *entry, gpointer user_data) {
777
const char *password1, *password2, *name, *cp;
779
password1 = gtk_entry_get_text(GTK_ENTRY(entry_new_account_password));
780
password2 = gtk_entry_get_text(GTK_ENTRY(entry_new_confirm_password));
781
name = gtk_entry_get_text(GTK_ENTRY(entry_new_account_name));
782
if (name && name[0] && password1 && password1[0] && password2 && password2[0]) {
783
do_account_create(name, password1, password2);
785
/* In this case, one, or more, of the fields is blank. If
786
* there were more than 3 widgets, I might but them into an
787
* array to make cycling easier
790
/* First case - if the currently active one is blank, no
791
* reason to move onward.
793
cp = gtk_entry_get_text(entry);
794
if (!cp || !cp[0]) return;
796
/* I'm not sure if it would make more sense to advance
797
* to the first NULL entry - but in that case, the pointer
798
* may hop in non intuitive ways - in this case, the user
799
* may just need to hit return a few times - MSW 2010/03/29
801
if (entry == GTK_ENTRY(entry_new_account_name))
802
gtk_widget_grab_focus(entry_new_account_password);
803
else if (entry == GTK_ENTRY(entry_new_account_password))
804
gtk_widget_grab_focus(entry_new_confirm_password);
805
else if (entry == GTK_ENTRY(entry_new_confirm_password))
806
gtk_widget_grab_focus(entry_new_account_name);
811
* This initializes the create account window and sets up the
814
static void init_create_account_window()
819
create_account_window = glade_xml_get_widget(dialog_xml, "create_account_window");
820
gtk_window_set_transient_for(GTK_WINDOW(create_account_window), GTK_WINDOW(window_root));
822
xml_tree = glade_get_widget_tree(GTK_WIDGET(create_account_window));
823
button_new_create_account = glade_xml_get_widget(dialog_xml,"button_new_create_account");
824
button_new_cancel = glade_xml_get_widget(dialog_xml,"button_new_cancel");
825
login_pane[TEXTVIEW_RULES_ACCOUNT].textview = glade_xml_get_widget(dialog_xml,"textview_rules_account");
826
textbuf_rules_account = gtk_text_view_get_buffer(
827
GTK_TEXT_VIEW(login_pane[TEXTVIEW_RULES_ACCOUNT].textview ));
828
entry_new_account_name = glade_xml_get_widget(dialog_xml,"entry_new_account_name");
829
entry_new_account_password = glade_xml_get_widget(dialog_xml,"entry_new_account_password");
830
entry_new_confirm_password = glade_xml_get_widget(dialog_xml,"entry_new_confirm_password");
831
label_create_account_status = glade_xml_get_widget(dialog_xml,"label_create_account_status");
833
add_tags_to_textbuffer(&login_pane[TEXTVIEW_RULES_ACCOUNT], textbuf_rules_account);
834
add_style_to_textbuffer(&login_pane[TEXTVIEW_RULES_ACCOUNT], NULL);
835
gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_RULES_ACCOUNT].textbuffer, &end);
836
login_pane[TEXTVIEW_RULES_ACCOUNT].textmark = gtk_text_buffer_create_mark(
837
login_pane[TEXTVIEW_RULES_ACCOUNT].textbuffer, NULL, &end, FALSE);
839
g_signal_connect ((gpointer) button_new_create_account, "clicked",
840
G_CALLBACK (on_button_new_create_account_clicked), NULL);
841
g_signal_connect ((gpointer) button_new_cancel, "clicked",
842
G_CALLBACK (on_button_new_cancel_clicked), NULL);
843
g_signal_connect ((gpointer) entry_new_account_name, "activate",
844
G_CALLBACK (on_entry_new_account), NULL);
845
g_signal_connect ((gpointer) entry_new_account_password, "activate",
846
G_CALLBACK (on_entry_new_account), NULL);
847
g_signal_connect ((gpointer) entry_new_confirm_password, "activate",
848
G_CALLBACK (on_entry_new_account), NULL);
853
/*****************************************************************************
855
*****************************************************************************/
858
* handles a failure from the server - pretty basic - just
859
* throw up the message and let the user try again.
861
void account_login_failure(char *message)
863
gtk_label_set_text(GTK_LABEL(label_account_login_status), message);
868
* User hit the create account button. So we need to hide the login
869
* window and bring up the create login window.
872
on_button_create_account_clicked (GtkButton *button, gpointer user_data)
874
gtk_widget_hide(login_window);
875
gtk_label_set_text(GTK_LABEL(label_create_account_status), "");
876
gtk_entry_set_text(GTK_ENTRY(entry_new_account_name), "");
877
gtk_entry_set_text(GTK_ENTRY(entry_new_account_password), "");
878
gtk_entry_set_text(GTK_ENTRY(entry_new_confirm_password), "");
879
gtk_widget_show(create_account_window);
883
* User hit the go to metaserver button. Need to disconnect from
884
* The server, and by clearing the csocket_fd, the main loop routine
885
* will bring up the metaserver window.
888
on_button_go_metaserver_clicked (GtkButton *button, gpointer user_data)
890
close_server_connection();
893
gdk_input_remove(csocket_fd);
900
* User hit the exit client button. Pretty simple in this case.
903
on_button_exit_client_clicked (GtkButton *button, gpointer user_data)
913
* This does the work of doing the login - mostly it just
914
* sends the request to the server. However, this might
915
* be called from either hitting the login button or
916
* entering data in name/password and hitting return.
918
static void do_account_login(const char *name, const char *password)
923
if (!name || !password || *name == 0 || *password == 0) {
924
gtk_label_set_text(GTK_LABEL(label_account_login_status),
925
"You must enter both a name and password!");
927
gtk_label_set_text(GTK_LABEL(label_account_login_status), "");
929
SockList_Init(&sl, buf);
930
SockList_AddString(&sl, "accountlogin ");
931
SockList_AddChar(&sl, strlen(name));
932
SockList_AddString(&sl, name);
933
SockList_AddChar(&sl, strlen(password));
934
SockList_AddString(&sl, password);
935
SockList_Send(&sl, csocket.fd);
936
/* Store password away for new character creation */
937
snprintf(account_password, 256, password);
942
* User hit the login button - just call do_account_login()
945
on_button_login_clicked (GtkButton *button, gpointer user_data)
947
do_account_login(gtk_entry_get_text(GTK_ENTRY(entry_account_name)),
948
gtk_entry_get_text(GTK_ENTRY(entry_account_password)));
952
* User hit return in the name entry box. If there is data in the password
953
* box, attempt login, otherwise make the password box active.
956
on_entry_account_name_activate (GtkEntry *entry, gpointer user_data) {
957
const char *password;
959
password = gtk_entry_get_text(GTK_ENTRY(entry_account_password));
961
if (!password || *password == 0) {
962
gtk_widget_grab_focus(entry_account_password);
964
do_account_login(gtk_entry_get_text(GTK_ENTRY(entry_account_name)), password);
969
* user hit return in the password box. Like above, if name data, do login,
970
* otherwise make the name box active.
973
on_entry_account_password_activate (GtkEntry *entry, gpointer user_data) {
976
name = gtk_entry_get_text(GTK_ENTRY(entry_account_name));
978
if (!name || *name == 0) {
979
gtk_widget_grab_focus(entry_account_name);
981
do_account_login(name, gtk_entry_get_text(GTK_ENTRY(entry_account_password)));
986
* This just sets up all the widget pointers, as well as setting
987
* up the callbacks for the login windows widgets.
989
static void init_login_window()
994
login_window = glade_xml_get_widget(dialog_xml, "login_window");
996
error_dialog("Out of date dialog.glade", "Did you run 'make install'?");
999
gtk_window_set_transient_for(GTK_WINDOW(login_window), GTK_WINDOW(window_root));
1001
xml_tree = glade_get_widget_tree(GTK_WIDGET(login_window));
1002
button_login = glade_xml_get_widget(dialog_xml,"button_login");
1003
button_create_account = glade_xml_get_widget(dialog_xml,"button_create_account");
1004
button_go_metaserver = glade_xml_get_widget(dialog_xml,"button_go_metaserver");
1005
button_exit_client = glade_xml_get_widget(dialog_xml,"button_exit_client");
1007
label_account_login_status = glade_xml_get_widget(dialog_xml,"label_account_login_status");
1009
login_pane[TEXTVIEW_MOTD].textview = glade_xml_get_widget(dialog_xml,"textview_motd");
1010
textbuf_motd = gtk_text_view_get_buffer(GTK_TEXT_VIEW(login_pane[TEXTVIEW_MOTD].textview));
1012
add_tags_to_textbuffer(&login_pane[TEXTVIEW_MOTD], textbuf_motd);
1013
add_style_to_textbuffer(&login_pane[TEXTVIEW_MOTD], NULL);
1014
gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_MOTD].textbuffer, &end);
1015
login_pane[TEXTVIEW_MOTD].textmark = gtk_text_buffer_create_mark(
1016
login_pane[TEXTVIEW_MOTD].textbuffer, NULL, &end, FALSE);
1018
login_pane[TEXTVIEW_NEWS].textview = glade_xml_get_widget(dialog_xml,"textview_news");
1019
textbuf_news = gtk_text_view_get_buffer(GTK_TEXT_VIEW(login_pane[TEXTVIEW_NEWS].textview));
1021
add_tags_to_textbuffer(&login_pane[TEXTVIEW_NEWS], textbuf_news);
1022
add_style_to_textbuffer(&login_pane[TEXTVIEW_NEWS], NULL);
1023
gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_NEWS].textbuffer, &end);
1024
login_pane[TEXTVIEW_NEWS].textmark = gtk_text_buffer_create_mark(
1025
login_pane[TEXTVIEW_NEWS].textbuffer, NULL, &end, FALSE);
1027
entry_account_name = glade_xml_get_widget(dialog_xml,"entry_account_name");
1028
entry_account_password = glade_xml_get_widget(dialog_xml,"entry_account_password");
1030
g_signal_connect ((gpointer) entry_account_name, "activate",
1031
G_CALLBACK (on_entry_account_name_activate), NULL);
1033
g_signal_connect ((gpointer) entry_account_password, "activate",
1034
G_CALLBACK (on_entry_account_password_activate), NULL);
1036
g_signal_connect ((gpointer) button_login, "clicked",
1037
G_CALLBACK (on_button_login_clicked), NULL);
1038
g_signal_connect ((gpointer) button_create_account, "clicked",
1039
G_CALLBACK (on_button_create_account_clicked), NULL);
1040
g_signal_connect ((gpointer) button_go_metaserver, "clicked",
1041
G_CALLBACK (on_button_go_metaserver_clicked), NULL);
1042
g_signal_connect ((gpointer) button_exit_client, "clicked",
1043
G_CALLBACK (on_button_exit_client_clicked), NULL);
1047
/*****************************************************************************
1048
* Common/generic functions
1049
****************************************************************************/
1052
* This is called from ReplyInfoCmd when it gets a response from
1053
* news/motd/rules. It is very possible that the window
1054
* will get displayed before we got a reply response, so
1055
* this tells the client to update it.
1058
* what data just got updated - text string of motd/news/rules
1060
void update_login_info(int type)
1063
if (!has_init) return;
1065
/* In all cases, we clear the buffer, and if we have
1066
* data, then set it to that data. This routine could
1069
if (type == INFO_NEWS) {
1070
gtk_text_buffer_set_text(textbuf_news, "", 0);
1072
/* the format of the news entry is special - there are a series
1073
* of %entries, and they are in reverse older (newest last)
1074
* we want to get rid of the %, make them more visible (convert them
1075
* to bold) and reverse the order.
1077
char *mynews, *cp, *el, big_buf[BIG_BUF], *cp1;
1079
mynews = strdup(news);
1080
/* We basically work from the end of the string going towards
1081
* the start looking for % characters. If we find one, we
1082
* have to make sure it is at the start of the line or start
1085
for (cp = mynews + strlen(mynews); cp > mynews; cp--) {
1086
if (*cp == '%' && (*(cp-1) == '\n' || cp == mynews)) {
1087
/* Find the end of the line */
1088
el = strchr(cp, '\n');
1089
/* null out the newline, put el one char beyond it */
1094
/* There isn't a clear standard - % news may be valid,
1095
* as might be %news. If % news is used, it looks better
1096
* to get rid of that leading space.
1099
while (isspace(*cp1)) cp1++;
1101
/* since we've null out the newline, this snprintf will
1102
* only get the % line and that is it. Mark it up
1104
snprintf(big_buf, BIG_BUF, "[b]%s[/b]", cp1);
1105
add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], big_buf, 0, 0, 0);
1106
/* Now we draw the text that goes with it, if it exists */
1108
add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], el, 0, 0, 0);
1110
/* Now we wipe the % out. In this way, the news buffer is shorter,
1111
* so when it draws the ext, there will just be that between the %
1112
* and the one we just wiped out.
1117
/* If there are remnants left over, or perhaps
1118
* the news file isn't formatted with % headers, display
1122
add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], mynews, 0, 0, 0);
1126
else if (type == INFO_MOTD) {
1127
gtk_text_buffer_set_text(textbuf_motd, "", 0);
1129
add_marked_text_to_pane(&login_pane[TEXTVIEW_MOTD], motd, 0, 0, 0);
1131
else if (type == INFO_RULES) {
1132
gtk_text_buffer_set_text(textbuf_rules_account, "", 0);
1133
gtk_text_buffer_set_text(textbuf_rules_char, "", 0);
1136
add_marked_text_to_pane(&login_pane[TEXTVIEW_RULES_ACCOUNT], rules, 0, 0, 0);
1137
add_marked_text_to_pane(&login_pane[TEXTVIEW_RULES_CHAR], rules, 0, 0, 0);
1145
* Starts the login process. If not already done, gets widgets,
1146
* sets up callboacks, etc. This is at the end of the file
1147
* so all the callbacks are defined before this function - in
1148
* that way, we do not need forward declarations.
1149
* This is called from SetupCmd in common/commands.c
1152
* login method that the server suppots.
1154
void start_login(int method)
1157
/* Store this away - if method is only 1, we can not
1158
* do smart character creation.
1160
serverloginmethod = method;
1163
/* Since there are 4 windows associated with account and character
1164
* login, to make life a little easier, each section here does
1165
* all the work for one window, so it is easier to see
1166
* that everything for a window is done - don't need to hunt
1167
* through what would otherwise be a long routine looking
1170
init_login_window();
1172
init_add_character_window();
1174
init_choose_char_window();
1176
init_create_account_window();
1178
init_new_character_window();
1182
/* In case we have gotten news/motd/rules before getting here,
1185
update_login_info(INFO_NEWS);
1186
update_login_info(INFO_RULES);
1187
update_login_info(INFO_MOTD);
1190
gtk_entry_set_text(GTK_ENTRY(entry_account_name), "");
1191
gtk_entry_set_text(GTK_ENTRY(entry_account_password), "");
1192
/* We set focus to account name - this makes the most sense if user is
1193
* logging in again - it is possible that the password is active,
1194
* but both fields are blank, which is not what is expected.
1196
gtk_widget_grab_focus(entry_account_name);
1197
gtk_widget_show(login_window);