~ubuntu-branches/ubuntu/maverick/crossfire-client/maverick

« back to all changes in this revision

Viewing changes to gtk-v2/src/account.c

  • Committer: Bazaar Package Importer
  • Author(s): Kari Pahula
  • Date: 2010-06-17 21:55:04 UTC
  • mfrom: (1.2.8 upstream) (3.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100617215504-864remyqayon6dot
Tags: 1.50.0-2
Install cfsndserv*, not cfsndserv_alsa9 to make kfreebsd land happy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
const char * const rcsid_gtk2_account_c =
 
2
    "$Id: account.c 12949 2010-04-25 07:07:43Z mwedel $";
 
3
/*
 
4
    Crossfire client, a client program for the crossfire program.
 
5
 
 
6
    Copyright (C) 2010 Mark Wedel & Crossfire Development Team
 
7
 
 
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.
 
12
 
 
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.
 
17
 
 
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.
 
21
 
 
22
    The author can be reached via e-mail to crossfire@metalforge.org
 
23
*/
 
24
 
 
25
/**
 
26
 * @file gtk-v2/src/account.c
 
27
 * Handles account login, creation, and character selection.
 
28
 */
 
29
 
 
30
#ifdef HAVE_CONFIG_H
 
31
#  include <config.h>
 
32
#endif
 
33
 
 
34
#include <gtk/gtk.h>
 
35
#include <glade/glade.h>
 
36
#include <ctype.h>
 
37
 
 
38
#include "client.h"
 
39
 
 
40
#include "image.h"
 
41
 
 
42
#include "main.h"
 
43
#include "gtk2proto.h"
 
44
#include "metaserver.h"
 
45
 
 
46
static GtkWidget *add_character_window, *choose_char_window,
 
47
 *create_account_window, *login_window;
 
48
 
 
49
/* These are in the login_window */
 
50
static GtkWidget *button_login, *button_create_account,
 
51
    *button_go_metaserver, *button_exit_client,
 
52
    *entry_account_name,
 
53
    *entry_account_password, *label_account_login_status;
 
54
 
 
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;
 
60
 
 
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;
 
65
 
 
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;
 
70
 
 
71
GtkListStore    *character_store;
 
72
 
 
73
static char account_password[256];
 
74
 
 
75
/* This enum just maps the columns in the list store to their
 
76
 * position.
 
77
 */
 
78
enum {CHAR_IMAGE, CHAR_NAME, CHAR_CLASS, CHAR_RACE, CHAR_LEVEL, CHAR_PARTY,
 
79
      CHAR_MAP, CHAR_ICON};
 
80
#define  CHAR_NUM_COLUMNS 8
 
81
 
 
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;
 
86
 
 
87
GtkTextBuffer *textbuf_motd, *textbuf_news, *textbuf_rules_account,
 
88
    *textbuf_rules_char;
 
89
 
 
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.
 
94
 */
 
95
#define TEXTVIEW_MOTD           0
 
96
#define TEXTVIEW_NEWS           1
 
97
#define TEXTVIEW_RULES_ACCOUNT  2
 
98
#define TEXTVIEW_RULES_CHAR     3
 
99
 
 
100
Info_Pane login_pane[4];
 
101
 
 
102
extern int num_text_views;
 
103
 
 
104
 
 
105
static int has_init=0;
 
106
 
 
107
 
 
108
/**
 
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
 
113
 * as AddMeSuccess
 
114
 */
 
115
void hide_all_login_windows()
 
116
{
 
117
    extern GtkWidget *treeview_look;
 
118
 
 
119
    if (has_init) {
 
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);
 
126
 
 
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
 
133
         * entry widget.
 
134
         */
 
135
        gtk_widget_grab_focus (GTK_WIDGET(treeview_look));
 
136
    }
 
137
 
 
138
}
 
139
 
 
140
/*****************************************************************************
 
141
 * New character window functions
 
142
 *****************************************************************************/
 
143
 
 
144
void create_new_character_failure(char *message)
 
145
{
 
146
        gtk_label_set_text(GTK_LABEL(label_new_char_status),
 
147
                           message);
 
148
}
 
149
 
 
150
static void create_new_character()
 
151
{
 
152
    const char *name;
 
153
    uint8 buf[MAX_BUF];
 
154
    SockList sl;
 
155
 
 
156
    SockList_Init(&sl, buf);
 
157
 
 
158
    name =  gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
 
159
 
 
160
    if (!name || *name == 0) {
 
161
        gtk_label_set_text(GTK_LABEL(label_new_char_status),
 
162
                           "You must enter a character name.");
 
163
        return;
 
164
    } else {
 
165
        gtk_label_set_text(GTK_LABEL(label_new_char_status),
 
166
                           "");
 
167
 
 
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);
 
174
    }
 
175
}
 
176
 
 
177
 
 
178
/**
 
179
 * User hit the create character button.  Get data, send to server.
 
180
 */
 
181
void
 
182
on_button_create_new_char_clicked (GtkButton *button, gpointer user_data)
 
183
{
 
184
    create_new_character();
 
185
}
 
186
 
 
187
/**
 
188
 * User hit return in the new character name box.  Like above,
 
189
 * get data and send to server.
 
190
 */
 
191
void on_entry_new_character_name(GtkEntry *entry, gpointer user_data)
 
192
{
 
193
    create_new_character();
 
194
}
 
195
 
 
196
/**
 
197
 * User his hit the cancel button in the new character window.
 
198
 * hide the new character window, show the choose character window.
 
199
 */
 
200
void
 
201
on_button_new_char_cancel_clicked(GtkButton *button, gpointer user_data)
 
202
{
 
203
    gtk_widget_hide(new_character_window);
 
204
    gtk_widget_show(choose_char_window);
 
205
}
 
206
 
 
207
 
 
208
 
 
209
/**
 
210
 * Initializes the new character window.
 
211
 */
 
212
static void init_new_character_window()
 
213
{
 
214
    GladeXML *xml_tree;                                                                                      
 
215
 
 
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));
 
218
 
 
219
    xml_tree = glade_get_widget_tree(GTK_WIDGET(new_character_window));
 
220
 
 
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");
 
226
 
 
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);
 
233
}
 
234
 
 
235
 
 
236
/******************************************************************************
 
237
 * add_character_window functions
 
238
 *****************************************************************************/
 
239
 
 
240
/**
 
241
 * This just sends a request to the server add add the
 
242
 * character to this account.
 
243
 */
 
244
static void add_character_to_account(const char *name, const char *password, int force)
 
245
{
 
246
    SockList sl;
 
247
    uint8 buf[MAX_BUF];
 
248
 
 
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!");
 
252
    } else {
 
253
        gtk_label_set_text(GTK_LABEL(label_add_status), "");
 
254
 
 
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);
 
263
    }
 
264
}
 
265
 
 
266
 
 
267
/**
 
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.
 
274
 *
 
275
 * @param message
 
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
 
279
 * to override this.
 
280
 */
 
281
void account_add_character_failure(char *message)
 
282
{
 
283
    char *cp;
 
284
    int retry;
 
285
 
 
286
    retry = atoi(message);
 
287
    cp = strchr(message,' ');
 
288
    if (cp) {
 
289
        cp++;
 
290
    } else
 
291
        cp=message;
 
292
 
 
293
    if (!retry) {
 
294
        gtk_label_set_text(GTK_LABEL(label_add_status), cp);
 
295
    } else {
 
296
        /* In this case, we can retry it and it should work
 
297
         * if we set force.
 
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
 
301
         * onward.
 
302
         */
 
303
        GtkWidget *dialog;
 
304
        int result;
 
305
        const char *name, *password;
 
306
 
 
307
        /* Bring up a dialog window */
 
308
        dialog = 
 
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);
 
313
 
 
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);
 
318
        } else {
 
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);
 
322
        }
 
323
    }
 
324
}
 
325
 
 
326
/**
 
327
 * User has hit the add character button.  Let add_character_to_account()
 
328
 * do all the work.
 
329
 *
 
330
 * @params ignored
 
331
 */
 
332
void
 
333
on_button_do_add_character_clicked (GtkButton *button, gpointer user_data)
 
334
{
 
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);
 
337
 
 
338
}
 
339
 
 
340
 
 
341
/**
 
342
 * User has hit the return to character selection button.  Pretty simple -
 
343
 * just hide this window, activate the other window.
 
344
 *
 
345
 * @params ignored
 
346
 */
 
347
void
 
348
on_button_return_character_select_clicked (GtkButton *button, gpointer user_data)
 
349
{
 
350
    gtk_widget_hide(add_character_window);
 
351
    gtk_widget_show(choose_char_window);
 
352
}
 
353
 
 
354
/**
 
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
 
358
 * to the other box.
 
359
 *
 
360
 * @param entry
 
361
 * Entry widget which generated this callback.
 
362
 */
 
363
void on_entry_character(GtkEntry *entry, gpointer user_data) {
 
364
    const char *name, *password;
 
365
 
 
366
    name =  gtk_entry_get_text(GTK_ENTRY(entry_character_name));
 
367
    password =  gtk_entry_get_text(GTK_ENTRY(entry_character_password));
 
368
 
 
369
    if (name && name[0] && password && password[0]) {
 
370
        add_character_to_account(name, password, 0);
 
371
    } else {
 
372
        const char *cp;
 
373
 
 
374
        /* First case - this widget is empty - do nothing */
 
375
        cp = gtk_entry_get_text(entry);
 
376
        if (!cp || !cp[0]) return;
 
377
 
 
378
        /* In this case, this widget is not empty - means the
 
379
         * other one is.
 
380
         */
 
381
        if (entry == GTK_ENTRY(entry_character_name))
 
382
            gtk_widget_grab_focus(entry_character_password);
 
383
        else
 
384
            gtk_widget_grab_focus(entry_character_name);
 
385
    }
 
386
}
 
387
 
 
388
 
 
389
 
 
390
static void init_add_character_window() {
 
391
    GladeXML *xml_tree;                                                                                      
 
392
 
 
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));
 
395
 
 
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");
 
403
 
 
404
    g_signal_connect ((gpointer) button_do_add_character, "clicked",
 
405
                      G_CALLBACK (on_button_do_add_character_clicked), NULL);
 
406
 
 
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);
 
413
}
 
414
 
 
415
/*****************************************************************************
 
416
 * choose_char_window
 
417
 ****************************************************************************/
 
418
 
 
419
/**
 
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
 
424
 * visible.
 
425
 */
 
426
void choose_character_init()
 
427
{
 
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);
 
432
 
 
433
    /* Store any old/stale entries */
 
434
    gtk_list_store_clear(character_store);
 
435
}
 
436
 
 
437
/**
 
438
 * User has done necessary steps to play a
 
439
 * character.
 
440
 */
 
441
static void play_character(const char *name)
 
442
{
 
443
    SockList sl;
 
444
    uint8 buf[MAX_BUF];
 
445
 
 
446
    SockList_Init(&sl, buf);
 
447
    SockList_AddString(&sl, "accountplay ");
 
448
    SockList_AddString(&sl, name);
 
449
    SockList_Send(&sl, csocket.fd);
 
450
}
 
451
 
 
452
/**
 
453
 * User has hit the play character button.  Grab
 
454
 * the selected entry, if there is one. 
 
455
 */
 
456
void
 
457
on_button_play_character_clicked (GtkButton *button, gpointer user_data)
 
458
{
 
459
    GtkTreeSelection *selected;
 
460
    GtkTreeModel    *model;
 
461
    GtkTreeIter iter;
 
462
    char *name;
 
463
 
 
464
    selected = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_choose_character));
 
465
 
 
466
    if (gtk_tree_selection_get_selected (selected, &model, &iter)) {
 
467
        gtk_tree_model_get(model, &iter, CHAR_NAME, &name, -1);
 
468
 
 
469
        play_character(name);
 
470
    }
 
471
}
 
472
 
 
473
void
 
474
on_button_create_character_clicked (GtkButton *button, gpointer user_data)
 
475
{
 
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), "");
 
479
}
 
480
 
 
481
/**
 
482
 * User has hit the add character button.
 
483
 * hide this window, show the add character window.
 
484
 */
 
485
void
 
486
on_button_add_character_clicked (GtkButton *button, gpointer user_data)
 
487
{
 
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);
 
493
}
 
494
 
 
495
/**
 
496
 * User has hit the return to login window.
 
497
 * hide this window, show the account login window.
 
498
 */
 
499
void
 
500
on_button_return_login_clicked(GtkButton *button, gpointer user_data)
 
501
{
 
502
    gtk_widget_hide(choose_char_window);
 
503
    gtk_widget_show(login_window);
 
504
}
 
505
 
 
506
/**
 
507
 * This gets data and adds it to the list store.  This is called
 
508
 * from AccountPlayersCmd and data is from the accountplayers protocol
 
509
 * command.
 
510
 *
 
511
 * @params ALL
 
512
 * data to add to the list store.
 
513
 */
 
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)
 
518
{
 
519
    GtkTreeIter iter;
 
520
 
 
521
    gtk_list_store_append(character_store, &iter);
 
522
 
 
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.
 
527
     */
 
528
    if (pixmaps[faceno] == pixmaps[0]) {    
 
529
        gtk_list_store_set(character_store, &iter,
 
530
                       CHAR_NAME, name,
 
531
                       CHAR_CLASS, class,
 
532
                       CHAR_RACE, race,
 
533
                       CHAR_IMAGE, face,
 
534
                       CHAR_PARTY, party,
 
535
                       CHAR_MAP, map,
 
536
                       CHAR_LEVEL, level,
 
537
                       -1);
 
538
    } else {
 
539
        gtk_list_store_set(character_store, &iter,
 
540
                       CHAR_ICON, pixmaps[faceno]->icon_image,
 
541
                       CHAR_NAME, name,
 
542
                       CHAR_CLASS, class,
 
543
                       CHAR_RACE, race,
 
544
                       CHAR_IMAGE, face,
 
545
                       CHAR_PARTY, party,
 
546
                       CHAR_MAP, map,
 
547
                       CHAR_LEVEL, level,
 
548
                       -1);
 
549
    }
 
550
 
 
551
}
 
552
 
 
553
 
 
554
/**
 
555
 * User has double clicked one of the character rows,
 
556
 * so use that character as the one to play.
 
557
 *
 
558
 * @param treeview
 
559
 * treeview which activated that (should always be treeview_choose_character)
 
560
 * @param path
 
561
 * mechanism to get to selected entry
 
562
 * @param column
 
563
 * activated column?
 
564
 * @param user_data
 
565
 * not set
 
566
 */
 
567
void on_treeview_choose_character_activated(GtkTreeView *treeview,
 
568
                                        GtkTreePath     *path,
 
569
                                        GtkTreeViewColumn *column,
 
570
                                        gpointer         user_data)
 
571
{
 
572
    GtkTreeIter iter;
 
573
    GtkTreeModel    *model;
 
574
    char *name;
 
575
 
 
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);
 
579
 
 
580
        if (!name) {
 
581
            LOG(LOG_ERROR,"account.c:on_treeview_choose_character_activated", "unable to get character name");
 
582
            return;
 
583
        }
 
584
        play_character(name);
 
585
    }
 
586
}
 
587
 
 
588
 
 
589
 
 
590
static void init_choose_char_window()
 
591
{
 
592
    GladeXML *xml_tree;                                                                                      
 
593
    GtkTextIter end;
 
594
    GtkCellRenderer *renderer;
 
595
    GtkTreeViewColumn *column;
 
596
 
 
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));
 
599
 
 
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");
 
609
 
 
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);
 
615
 
 
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);
 
626
 
 
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));
 
634
 
 
635
    renderer = gtk_cell_renderer_pixbuf_new();
 
636
    column = gtk_tree_view_column_new_with_attributes ("?", renderer,
 
637
                                                       "pixbuf", CHAR_ICON,
 
638
                                                      NULL);
 
639
 
 
640
    gtk_tree_view_column_set_min_width(column, image_size);
 
641
    gtk_tree_view_append_column (GTK_TREE_VIEW(treeview_choose_character), column);
 
642
 
 
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);
 
648
 
 
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);
 
654
 
 
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);
 
660
 
 
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);
 
666
 
 
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);
 
672
 
 
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);
 
678
 
 
679
}
 
680
 
 
681
/******************************************************************************
 
682
 * create_account_window
 
683
 ******************************************************************************/
 
684
 
 
685
/**
 
686
 * handles a failure from the server - pretty basic - just
 
687
 * throw up the message and let the user try again.
 
688
 */
 
689
void account_creation_failure(char *message)
 
690
{
 
691
    gtk_label_set_text(GTK_LABEL(label_create_account_status), message);
 
692
}
 
693
 
 
694
/**
 
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();
 
700
 *
 
701
 * @param name
 
702
 * desired account name - must not be NULL.
 
703
 * @param p1
 
704
 * the first password - must not be NULL
 
705
 * @param p2
 
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
 
708
 */
 
709
static void do_account_create(const char *name, const char *p1, const char *p2)
 
710
{
 
711
    SockList sl;
 
712
    uint8 buf[MAX_BUF];
 
713
 
 
714
    if (strcmp(p1, p2)) {
 
715
        gtk_label_set_text(GTK_LABEL(label_create_account_status),
 
716
                      "The passwords you entered do not match!");
 
717
        return;
 
718
    } else {
 
719
        gtk_label_set_text(GTK_LABEL(label_create_account_status),
 
720
                      "");
 
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);
 
730
    }
 
731
}
 
732
 
 
733
/**
 
734
 * User clicked on the create account button.  In this case,
 
735
 * we just process the data and call do_account_create();
 
736
 */
 
737
void
 
738
on_button_new_create_account_clicked (GtkButton *button, gpointer user_data)
 
739
{
 
740
    const char *password1, *password2, *name;
 
741
 
 
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));
 
745
 
 
746
    if (name && name[0] && password1 && password1[0] && password2 && password2[0]) {
 
747
        do_account_create(name, password1, password2);
 
748
    } else {
 
749
        gtk_label_set_text(GTK_LABEL(label_create_account_status),
 
750
                      "You must fill in all three entries!");
 
751
    }
 
752
}
 
753
 
 
754
void
 
755
on_button_new_cancel_clicked (GtkButton *button, gpointer user_data)
 
756
{
 
757
    gtk_widget_hide(create_account_window);
 
758
    gtk_widget_show(login_window);
 
759
}
 
760
 
 
761
/**
 
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
 
767
 * to the next box.
 
768
 *
 
769
 * @params entry
 
770
 * entry box - we use this to figure out what the next box is.
 
771
 * @params user_data
 
772
 * not used.
 
773
 */
 
774
void
 
775
on_entry_new_account (GtkEntry *entry, gpointer user_data) {
 
776
 
 
777
    const char *password1, *password2, *name, *cp;
 
778
 
 
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);
 
784
    } else {
 
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
 
788
         */
 
789
 
 
790
        /* First case - if the currently active one is blank, no
 
791
         * reason to move onward.
 
792
         */
 
793
        cp = gtk_entry_get_text(entry);
 
794
        if (!cp || !cp[0]) return;
 
795
 
 
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
 
800
         */
 
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);
 
807
    }
 
808
}
 
809
 
 
810
/**
 
811
 * This initializes the create account window and sets up the
 
812
 * various callbacks.
 
813
 */
 
814
static void init_create_account_window()
 
815
{
 
816
    GladeXML *xml_tree;                                                                              
 
817
    GtkTextIter end;
 
818
 
 
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));
 
821
 
 
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");
 
832
 
 
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);
 
838
 
 
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);
 
849
 
 
850
}
 
851
 
 
852
 
 
853
/*****************************************************************************
 
854
 * login_window
 
855
 *****************************************************************************/
 
856
 
 
857
/**
 
858
 * handles a failure from the server - pretty basic - just
 
859
 * throw up the message and let the user try again.
 
860
 */
 
861
void account_login_failure(char *message)
 
862
{
 
863
    gtk_label_set_text(GTK_LABEL(label_account_login_status), message);
 
864
}
 
865
 
 
866
 
 
867
/**
 
868
 * User hit the create account button.  So we need to hide the login
 
869
 * window and bring up the create login window.
 
870
 */
 
871
void
 
872
on_button_create_account_clicked (GtkButton *button, gpointer user_data)
 
873
{
 
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);
 
880
}
 
881
 
 
882
/**
 
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.
 
886
 */
 
887
void
 
888
on_button_go_metaserver_clicked (GtkButton *button, gpointer user_data)
 
889
{
 
890
    close_server_connection();
 
891
 
 
892
    if (csocket_fd) {
 
893
        gdk_input_remove(csocket_fd);
 
894
        csocket_fd=0;
 
895
        gtk_main_quit();
 
896
    }
 
897
}
 
898
 
 
899
/**
 
900
 * User hit the exit client button.  Pretty simple in this case.
 
901
 */
 
902
void
 
903
on_button_exit_client_clicked (GtkButton *button, gpointer user_data)
 
904
{
 
905
#ifdef WIN32
 
906
    script_killall();
 
907
#endif
 
908
    exit(0);
 
909
}
 
910
 
 
911
 
 
912
/**
 
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.
 
917
 */
 
918
static void do_account_login(const char *name, const char *password)
 
919
{
 
920
    SockList sl;
 
921
    uint8 buf[MAX_BUF];
 
922
 
 
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!");
 
926
    } else {
 
927
        gtk_label_set_text(GTK_LABEL(label_account_login_status), "");
 
928
 
 
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);
 
938
    }
 
939
}
 
940
 
 
941
/**
 
942
 * User hit the login button - just call do_account_login()
 
943
 */
 
944
void
 
945
on_button_login_clicked (GtkButton *button, gpointer user_data)
 
946
{
 
947
    do_account_login(gtk_entry_get_text(GTK_ENTRY(entry_account_name)),
 
948
                     gtk_entry_get_text(GTK_ENTRY(entry_account_password)));
 
949
}
 
950
 
 
951
/**
 
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.
 
954
 */
 
955
void
 
956
on_entry_account_name_activate (GtkEntry *entry, gpointer user_data) {
 
957
    const char *password;
 
958
 
 
959
    password = gtk_entry_get_text(GTK_ENTRY(entry_account_password));
 
960
 
 
961
    if (!password || *password == 0) {
 
962
        gtk_widget_grab_focus(entry_account_password);
 
963
    } else {
 
964
        do_account_login(gtk_entry_get_text(GTK_ENTRY(entry_account_name)), password);
 
965
    }
 
966
}
 
967
 
 
968
/**
 
969
 * user hit return in the password box.  Like above, if name data, do login,
 
970
 * otherwise make the name box active.
 
971
 */
 
972
void
 
973
on_entry_account_password_activate (GtkEntry *entry, gpointer user_data) {
 
974
    const char *name;
 
975
 
 
976
    name = gtk_entry_get_text(GTK_ENTRY(entry_account_name));
 
977
 
 
978
    if (!name || *name == 0) {
 
979
        gtk_widget_grab_focus(entry_account_name);
 
980
    } else {
 
981
        do_account_login(name, gtk_entry_get_text(GTK_ENTRY(entry_account_password)));
 
982
    }
 
983
}
 
984
 
 
985
/**
 
986
 * This just sets up all the widget pointers, as well as setting
 
987
 * up the callbacks for the login windows widgets.
 
988
 */
 
989
static void init_login_window()
 
990
{
 
991
    GladeXML *xml_tree;
 
992
    GtkTextIter end;
 
993
 
 
994
    login_window = glade_xml_get_widget(dialog_xml, "login_window");
 
995
    if (!login_window) {
 
996
        error_dialog("Out of date dialog.glade", "Did you run 'make install'?");
 
997
        exit(1);
 
998
    }
 
999
    gtk_window_set_transient_for(GTK_WINDOW(login_window), GTK_WINDOW(window_root));
 
1000
 
 
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");
 
1006
 
 
1007
    label_account_login_status = glade_xml_get_widget(dialog_xml,"label_account_login_status");
 
1008
 
 
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));
 
1011
 
 
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);
 
1017
 
 
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));
 
1020
 
 
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);
 
1026
 
 
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");
 
1029
 
 
1030
    g_signal_connect ((gpointer) entry_account_name, "activate",
 
1031
                      G_CALLBACK (on_entry_account_name_activate), NULL);
 
1032
 
 
1033
    g_signal_connect ((gpointer) entry_account_password, "activate",
 
1034
                      G_CALLBACK (on_entry_account_password_activate), NULL);
 
1035
 
 
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);
 
1044
 
 
1045
}
 
1046
 
 
1047
/*****************************************************************************
 
1048
 * Common/generic functions
 
1049
 ****************************************************************************/
 
1050
 
 
1051
/**
 
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.
 
1056
 *
 
1057
 *@params type
 
1058
 * what data just got updated - text string of motd/news/rules
 
1059
 */
 
1060
void update_login_info(int type)
 
1061
{
 
1062
 
 
1063
    if (!has_init) return;
 
1064
 
 
1065
    /* In all cases, we clear the buffer, and if we have
 
1066
     * data, then set it to that data.  This routine could
 
1067
     * be smarter an
 
1068
     */
 
1069
    if (type == INFO_NEWS) {
 
1070
        gtk_text_buffer_set_text(textbuf_news, "", 0);
 
1071
        if (news) {
 
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.
 
1076
             */
 
1077
            char *mynews, *cp, *el, big_buf[BIG_BUF], *cp1;
 
1078
 
 
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
 
1083
             * of the buffer
 
1084
             */
 
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 */
 
1090
                    if (el) {
 
1091
                        *el=0;
 
1092
                        el++;
 
1093
                    }
 
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.
 
1097
                     */
 
1098
                    cp1 = cp+1;
 
1099
                    while (isspace(*cp1)) cp1++;
 
1100
 
 
1101
                    /* since we've null out the newline, this snprintf will
 
1102
                     * only get the % line and that is it.  Mark it up
 
1103
                     */
 
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 */
 
1107
                    if (el)
 
1108
                        add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], el, 0, 0, 0);
 
1109
 
 
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.
 
1113
                     */
 
1114
                    *cp = 0;
 
1115
                }
 
1116
            }
 
1117
            /* If there are remnants left over, or perhaps
 
1118
             * the news file isn't formatted with % headers, display
 
1119
             * what we have got.
 
1120
             */
 
1121
            if (*mynews != 0)
 
1122
                add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], mynews, 0, 0, 0);
 
1123
 
 
1124
        }
 
1125
    }
 
1126
    else if (type == INFO_MOTD) {
 
1127
        gtk_text_buffer_set_text(textbuf_motd, "", 0);
 
1128
        if (motd) 
 
1129
            add_marked_text_to_pane(&login_pane[TEXTVIEW_MOTD], motd, 0, 0, 0);
 
1130
    }
 
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);
 
1134
 
 
1135
        if (rules) {
 
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);
 
1138
        }
 
1139
    }
 
1140
 
 
1141
}
 
1142
 
 
1143
 
 
1144
/**
 
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
 
1150
 *
 
1151
 * @param method
 
1152
 * login method that the server suppots.
 
1153
 */
 
1154
void start_login(int method)
 
1155
{
 
1156
 
 
1157
    /* Store this away - if method is only 1, we can not
 
1158
     * do smart character creation.
 
1159
     */
 
1160
    serverloginmethod = method;
 
1161
 
 
1162
    if (!has_init) {
 
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
 
1168
         * for entries.
 
1169
         */
 
1170
        init_login_window();
 
1171
 
 
1172
        init_add_character_window();
 
1173
 
 
1174
        init_choose_char_window();
 
1175
 
 
1176
        init_create_account_window();
 
1177
 
 
1178
        init_new_character_window();
 
1179
 
 
1180
        has_init=1;
 
1181
 
 
1182
        /* In case we have gotten news/motd/rules before getting here, 
 
1183
         * update it now.
 
1184
         */
 
1185
        update_login_info(INFO_NEWS);
 
1186
        update_login_info(INFO_RULES);
 
1187
        update_login_info(INFO_MOTD);
 
1188
    }
 
1189
 
 
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.
 
1195
     */
 
1196
    gtk_widget_grab_focus(entry_account_name);
 
1197
    gtk_widget_show(login_window);
 
1198
 
 
1199
}
 
1200