~ubuntu-branches/ubuntu/edgy/ggz-client-libs/edgy

« back to all changes in this revision

Viewing changes to ggzcore/netxml.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Eisentraut, Josef Spillner, Peter Eisentraut
  • Date: 2006-09-09 13:37:14 UTC
  • mfrom: (2.1.2 edgy)
  • Revision ID: james.westby@ubuntu.com-20060909133714-q49a9kvjfkc0wcc3
Tags: 0.0.13-3
[ Josef Spillner ]
* Change ggzcore-bin dependency from ggzmod to recommends from ggzcore
  (closes: #384671).

[ Peter Eisentraut ]
* Make package dependencies binNMU-safe through use of ${binary:Version}
  (closes: #386126)

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 * Author: Brent Hendricks
4
4
 * Project: GGZ Core Client Lib
5
5
 * Date: 9/22/00
6
 
 * $Id: netxml.c,v 1.67 2003/05/10 06:52:48 dr_maux Exp $
 
6
 * $Id: netxml.c 7909 2006-03-14 13:50:27Z josef $
7
7
 *
8
8
 * Code for parsing XML streamed from the server
9
9
 *
10
10
 * Copyright (C) 2000 Brent Hendricks.
11
11
 *
12
 
 * This program is free software; you can redistribute it and/or modify
13
 
 * it under the terms of the GNU General Public License as published by
14
 
 * the Free Software Foundation; either version 2 of the License, or
15
 
 * (at your option) any later version.
16
 
 *
17
 
 * This program is distributed in the hope that it will be useful,
 
12
 * This library is free software; you can redistribute it and/or
 
13
 * modify it under the terms of the GNU Lesser General Public
 
14
 * License as published by the Free Software Foundation; either
 
15
 * version 2.1 of the License, or (at your option) any later version.
 
16
 * 
 
17
 * This library is distributed in the hope that it will be useful,
18
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 
 * GNU General Public License for more details.
21
 
 *
22
 
 * You should have received a copy of the GNU General Public License
23
 
 * along with this program; if not, write to the Free Software
24
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
20
 * Lesser General Public License for more details.
 
21
 * 
 
22
 * You should have received a copy of the GNU Lesser General Public
 
23
 * License along with this library; if not, write to the Free Software
 
24
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25
25
 */
26
26
 
27
27
#ifdef HAVE_CONFIG_H
28
 
#  include <config.h>           /* Site-specific config */
 
28
#  include <config.h>   /* Site-specific config */
29
29
#endif
30
30
 
31
31
#include <errno.h>
32
32
#include <fcntl.h>
33
33
#include <limits.h>
34
 
#include <poll.h>
35
34
#include <stdio.h>
36
35
#include <stdlib.h>
37
36
#include <string.h>
 
37
#include <strings.h>
38
38
#include <sys/stat.h>
39
39
#include <sys/types.h>
40
40
#include <unistd.h>
41
41
 
 
42
#ifdef HAVE_WINSOCK2_H
 
43
# include <winsock2.h>
 
44
#endif
 
45
 
42
46
#include <expat.h>
43
47
#include <ggz.h>
44
48
#include <ggz_common.h>
50
54
#include "room.h"
51
55
#include "state.h"
52
56
#include "table.h"
 
57
#include "game.h"
53
58
#include "gametype.h"
54
59
 
55
60
/* For convenience */
60
65
 
61
66
/* GGZNet structure for handling the network connection to the server */
62
67
struct _GGZNet {
63
 
        
 
68
 
64
69
        /* Server structure handling this session */
65
70
        GGZServer *server;
66
 
        
 
71
 
67
72
        /* Host name of server */
68
73
        const char *host;
69
74
 
76
81
        /* Maximum chat size allowed */
77
82
        unsigned int chat_size;
78
83
 
79
 
        /* Room to which we are transitioning */
80
 
        GGZRoom *new_room;
81
 
 
82
84
        /* Room verbosity (need to save) */
83
85
        char room_verbose;
84
86
 
95
97
        GGZStack *stack;
96
98
 
97
99
        /* File to dump protocol session */
98
 
        int dump_file;
 
100
        FILE *dump_file;
99
101
 
100
102
        /* Whether to use TLS or not */
101
103
        int use_tls;
102
104
};
103
105
 
104
 
 
105
106
/* Game data structure */
106
107
typedef struct {
107
108
        const char *prot_engine;
109
110
        GGZNumberList player_allow_list;
110
111
        GGZNumberList bot_allow_list;
111
112
        int spectators_allow;
 
113
        int peers_allow;
112
114
        const char *desc;
113
115
        const char *author;
114
116
        const char *url;
115
 
} GGZGameData;  
 
117
        char ***named_bots;
 
118
} GGZGameData;
 
119
 
 
120
/* Player information structure */
 
121
typedef struct {
 
122
        int num;
 
123
        const char *realname;
 
124
        const char *photo;
 
125
        const char *host;
 
126
} GGZPlayerInfo;
 
127
typedef struct {
 
128
        GGZList *infos;
 
129
} GGZPlayerInfoData;
116
130
 
117
131
/* Table data structure */
118
132
typedef struct {
123
137
 
124
138
 
125
139
/* Callbacks for XML parser */
126
 
static void _ggzcore_net_parse_start_tag(void *, const char*, const char **);
 
140
static void _ggzcore_net_parse_start_tag(void *data, const char *el,
 
141
                                         const char **attr);
127
142
static void _ggzcore_net_parse_end_tag(void *data, const char *el);
128
143
static void _ggzcore_net_parse_text(void *data, const char *text, int len);
129
 
static GGZXMLElement* _ggzcore_net_new_element(char *tag, char **attrs);
 
144
static GGZXMLElement *_ggzcore_net_new_element(const char *tag,
 
145
                                               const char *const *attrs);
130
146
 
131
147
/* Handler functions for various tags */
132
 
static void _ggzcore_net_handle_server(GGZNet*, GGZXMLElement*);
133
 
static void _ggzcore_net_handle_options(GGZNet*, GGZXMLElement*);
134
 
static void _ggzcore_net_handle_motd(GGZNet*, GGZXMLElement*);
135
 
static void _ggzcore_net_handle_result(GGZNet*, GGZXMLElement*);
136
 
static void _ggzcore_net_handle_password(GGZNet *net, GGZXMLElement*);
137
 
static void _ggzcore_net_handle_list(GGZNet*, GGZXMLElement*);
138
 
static void _ggzcore_net_handle_update(GGZNet*, GGZXMLElement*);
139
 
static void _ggzcore_net_handle_game(GGZNet*, GGZXMLElement*);
140
 
static void _ggzcore_net_handle_protocol(GGZNet*, GGZXMLElement*);
141
 
static void _ggzcore_net_handle_allow(GGZNet*, GGZXMLElement*);
142
 
static void _ggzcore_net_handle_about(GGZNet*, GGZXMLElement*);
143
 
static void _ggzcore_net_handle_desc(GGZNet*, GGZXMLElement*);
144
 
static void _ggzcore_net_handle_room(GGZNet*, GGZXMLElement*);
145
 
static void _ggzcore_net_handle_player(GGZNet*, GGZXMLElement*);
146
 
static void _ggzcore_net_handle_table(GGZNet*, GGZXMLElement*);
147
 
static void _ggzcore_net_handle_seat(GGZNet*, GGZXMLElement*);
148
 
static void _ggzcore_net_handle_spectator_seat(GGZNet *net,
149
 
                                               GGZXMLElement *seat);
150
 
static void _ggzcore_net_handle_chat(GGZNet*, GGZXMLElement*);
151
 
static void _ggzcore_net_handle_leave(GGZNet *net, GGZXMLElement *element);
152
 
static void _ggzcore_net_handle_join(GGZNet *net, GGZXMLElement *element);
153
 
static void _ggzcore_net_handle_ping(GGZNet*, GGZXMLElement*);
154
 
static void _ggzcore_net_handle_session(GGZNet*, GGZXMLElement*);
 
148
static void _ggzcore_net_handle_server(GGZNet *, GGZXMLElement *);
 
149
static void _ggzcore_net_handle_options(GGZNet *, GGZXMLElement *);
 
150
static void _ggzcore_net_handle_motd(GGZNet *, GGZXMLElement *);
 
151
static void _ggzcore_net_handle_result(GGZNet *, GGZXMLElement *);
 
152
static void _ggzcore_net_handle_password(GGZNet * net, GGZXMLElement *);
 
153
static void _ggzcore_net_handle_list(GGZNet *, GGZXMLElement *);
 
154
static void _ggzcore_net_handle_update(GGZNet *, GGZXMLElement *);
 
155
static void _ggzcore_net_handle_game(GGZNet *, GGZXMLElement *);
 
156
static void _ggzcore_net_handle_protocol(GGZNet *, GGZXMLElement *);
 
157
static void _ggzcore_net_handle_allow(GGZNet *, GGZXMLElement *);
 
158
static void _ggzcore_net_handle_about(GGZNet *, GGZXMLElement *);
 
159
static void _ggzcore_net_handle_bot(GGZNet *, GGZXMLElement *);
 
160
static void _ggzcore_net_handle_desc(GGZNet *, GGZXMLElement *);
 
161
static void _ggzcore_net_handle_room(GGZNet *, GGZXMLElement *);
 
162
static void _ggzcore_net_handle_player(GGZNet *, GGZXMLElement *);
 
163
static void _ggzcore_net_handle_table(GGZNet *, GGZXMLElement *);
 
164
static void _ggzcore_net_handle_seat(GGZNet *, GGZXMLElement *);
 
165
static void _ggzcore_net_handle_spectator_seat(GGZNet * net,
 
166
                                               GGZXMLElement * seat);
 
167
static void _ggzcore_net_handle_chat(GGZNet *, GGZXMLElement *);
 
168
static void _ggzcore_net_handle_info(GGZNet *, GGZXMLElement *);
 
169
static void _ggzcore_net_handle_playerinfo(GGZNet *, GGZXMLElement *);
 
170
static void _ggzcore_net_handle_leave(GGZNet * net,
 
171
                                      GGZXMLElement * element);
 
172
static void _ggzcore_net_handle_join(GGZNet * net,
 
173
                                     GGZXMLElement * element);
 
174
static void _ggzcore_net_handle_ping(GGZNet *, GGZXMLElement *);
 
175
static void _ggzcore_net_handle_session(GGZNet *, GGZXMLElement *);
155
176
 
156
177
/* Extra functions fot handling data associated with specific tags */
157
 
static void _ggzcore_net_list_insert(GGZXMLElement*, void*);
158
 
static GGZGameData *_ggzcore_net_game_get_data(GGZXMLElement *game);
159
 
static void _ggzcore_net_game_set_protocol(GGZXMLElement*, char*, char *);
160
 
static void _ggzcore_net_game_set_allowed(GGZXMLElement*,
161
 
                                          GGZNumberList, GGZNumberList, int);
162
 
static void _ggzcore_net_game_set_info(GGZXMLElement*, char*, char *);
163
 
static void _ggzcore_net_game_set_desc(GGZXMLElement*, char*);
164
 
static void _ggzcore_net_table_add_seat(GGZXMLElement*, struct _GGZSeat*,
 
178
static void _ggzcore_net_list_insert(GGZXMLElement *, void *);
 
179
static GGZGameData *_ggzcore_net_game_get_data(GGZXMLElement * game);
 
180
static void _ggzcore_net_game_set_protocol(GGZXMLElement * game,
 
181
                                           const char *engine,
 
182
                                           const char *version);
 
183
static void _ggzcore_net_game_set_allowed(GGZXMLElement *,
 
184
                                          GGZNumberList, GGZNumberList,
 
185
                                          int, int);
 
186
static void _ggzcore_net_game_set_info(GGZXMLElement *, const char *,
 
187
                                       const char *);
 
188
static void _ggzcore_net_game_add_bot(GGZXMLElement *, const char *,
 
189
                                       const char *);
 
190
static void _ggzcore_net_game_set_desc(GGZXMLElement *, char *);
 
191
static void _ggzcore_net_table_add_seat(GGZXMLElement *, GGZTableSeat *,
165
192
                                        int spectator);
166
 
static void _ggzcore_net_player_update(GGZNet *net, GGZXMLElement *update, char *action);
167
 
static void _ggzcore_net_table_update(GGZNet *net, GGZXMLElement *update, char *action);
168
 
static GGZTableData *_ggzcore_net_table_get_data(GGZXMLElement *table);
169
 
static void _ggzcore_net_table_set_desc(GGZXMLElement*, char*);
170
 
static GGZTableData* _ggzcore_net_tabledata_new(void);
171
 
static void _ggzcore_net_tabledata_free(GGZTableData*);
172
 
static struct _GGZSeat* _ggzcore_net_seat_copy(struct _GGZSeat *orig);
173
 
static void _ggzcore_net_seat_free(struct _GGZSeat*);
 
193
static void _ggzcore_net_room_update(GGZNet * net, GGZXMLElement * update,
 
194
                                     const char *action);
 
195
static void _ggzcore_net_player_update(GGZNet * net,
 
196
                                       GGZXMLElement * update,
 
197
                                       const char *action);
 
198
static void _ggzcore_net_table_update(GGZNet * net, GGZXMLElement * update,
 
199
                                      const char *action);
 
200
static GGZTableData *_ggzcore_net_table_get_data(GGZXMLElement * table);
 
201
static void _ggzcore_net_table_set_desc(GGZXMLElement *, char *);
 
202
static GGZTableData *_ggzcore_net_tabledata_new(void);
 
203
static void _ggzcore_net_tabledata_free(GGZTableData *);
 
204
static GGZTableSeat *_ggzcore_net_seat_copy(GGZTableSeat * orig);
 
205
static void _ggzcore_net_seat_free(GGZTableSeat *);
 
206
 
 
207
static GGZPlayerInfoData *_ggzcore_net_playerinfo_get_data(GGZXMLElement * game);
 
208
static void _ggzcore_net_playerinfo_add_seat(GGZXMLElement *, int,
 
209
                                       const char *, const char *, const char *);
174
210
 
175
211
/* Trigger network error event */
176
 
static void _ggzcore_net_error(GGZNet *net, char* message);
 
212
static void _ggzcore_net_error(GGZNet * net, char *message);
177
213
 
178
214
/* Dump network data to debugging file */
179
 
static void _ggzcore_net_dump_data(GGZNet *net, char *data, int size);
180
 
static void _ggzcore_net_negotiate_tls(GGZNet *net);
 
215
static void _ggzcore_net_dump_data(GGZNet * net, char *data, int size);
 
216
static void _ggzcore_net_negotiate_tls(GGZNet * net);
181
217
 
182
218
/* Utility functions */
183
 
static int _ggzcore_net_send_table_seat(GGZNet *net, struct _GGZSeat *seat);
184
 
static void _ggzcore_net_send_header(GGZNet *net);
185
 
static int _ggzcore_net_send_pong(GGZNet *net, const char *id);
186
 
static int _ggzcore_net_send_line(GGZNet *net, char *line, ...)
187
 
        ggz__attribute((format(printf, 2, 3)));
 
219
static int _ggzcore_net_send_table_seat(GGZNet * net, GGZTableSeat * seat);
 
220
static void _ggzcore_net_send_header(GGZNet * net);
 
221
static int _ggzcore_net_send_pong(GGZNet * net, const char *id);
 
222
static int _ggzcore_net_send_line(GGZNet * net, char *line, ...)
 
223
ggz__attribute((format(printf, 2, 3)));
188
224
static int str_to_int(const char *str, int dflt);
189
225
 
190
226
 
191
227
 
192
228
/* Internal library functions (prototypes in net.h) */
193
229
 
194
 
GGZNet* _ggzcore_net_new(void)
 
230
GGZNet *_ggzcore_net_new(void)
195
231
{
196
232
        GGZNet *net;
197
233
 
198
234
        net = ggz_malloc(sizeof(GGZNet));
199
 
        
 
235
 
200
236
        /* Set fd to invalid value */
201
237
        net->fd = -1;
202
 
        net->dump_file = -1;
 
238
        net->dump_file = NULL;
203
239
        net->use_tls = -1;
204
 
        
 
240
 
205
241
        return net;
206
242
}
207
243
 
208
244
 
209
 
void _ggzcore_net_init(GGZNet *net, GGZServer *server,
210
 
                       const char *host, unsigned int port, unsigned int use_tls)
 
245
void _ggzcore_net_init(GGZNet * net, GGZServer * server,
 
246
                       const char *host, unsigned int port,
 
247
                       unsigned int use_tls)
211
248
{
212
249
        net->server = server;
213
250
        net->host = ggz_strdup(host);
217
254
 
218
255
        /* Init parser */
219
256
        if (!(net->parser = XML_ParserCreate("UTF-8")))
220
 
                ggz_error_sys_exit("Couldn't allocate memory for XML parser");
 
257
                ggz_error_sys_exit
 
258
                    ("Couldn't allocate memory for XML parser");
221
259
 
222
260
        /* Setup handlers for tags */
223
 
        XML_SetElementHandler(net->parser, 
224
 
                              _ggzcore_net_parse_start_tag, 
 
261
        XML_SetElementHandler(net->parser, (XML_StartElementHandler)
 
262
                              _ggzcore_net_parse_start_tag,
 
263
                              (XML_EndElementHandler)
225
264
                              _ggzcore_net_parse_end_tag);
226
265
        XML_SetCharacterDataHandler(net->parser, _ggzcore_net_parse_text);
227
266
        XML_SetUserData(net->parser, net);
231
270
}
232
271
 
233
272
 
234
 
int _ggzcore_net_set_dump_file(GGZNet *net, const char* filename)
 
273
int _ggzcore_net_set_dump_file(GGZNet * net, const char *filename)
235
274
{
236
275
        if (!filename)
237
276
                return 0;
238
 
        
 
277
 
239
278
        if (strcasecmp(filename, "stderr") == 0)
240
 
                net->dump_file = STDERR_FILENO;
 
279
                net->dump_file = stderr;
241
280
        else
242
 
                net->dump_file = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
243
 
        
 
281
                net->dump_file = fopen(filename, "w");
 
282
 
244
283
        if (net->dump_file < 0)
245
284
                return -1;
246
285
        else
248
287
}
249
288
 
250
289
 
251
 
const char* _ggzcore_net_get_host(GGZNet *net)
 
290
const char *_ggzcore_net_get_host(GGZNet * net)
252
291
{
253
292
        return net->host;
254
293
}
255
294
 
256
295
 
257
 
unsigned int _ggzcore_net_get_port(GGZNet *net)
 
296
unsigned int _ggzcore_net_get_port(GGZNet * net)
258
297
{
259
298
        return net->port;
260
299
}
261
300
 
262
301
 
263
 
int _ggzcore_net_get_fd(GGZNet *net)
 
302
int _ggzcore_net_get_fd(GGZNet * net)
264
303
{
265
304
        return net->fd;
266
305
}
267
306
 
268
307
 
269
 
int _ggzcore_net_get_tls(struct _GGZNet *net)
 
308
int _ggzcore_net_get_tls(GGZNet * net)
270
309
{
271
310
        return net->use_tls;
272
311
}
273
312
 
274
313
 
275
314
/* For debugging purposes only! */
276
 
void _ggzcore_net_set_fd(GGZNet *net, int fd)
 
315
void _ggzcore_net_set_fd(GGZNet * net, int fd)
277
316
{
278
317
        net->fd = fd;
279
318
}
280
319
 
281
 
void _ggzcore_net_free(GGZNet *net)
 
320
void _ggzcore_net_free(GGZNet * net)
282
321
{
283
322
        GGZXMLElement *element;
284
323
 
285
324
        if (net->fd >= 0)
286
325
                _ggzcore_net_disconnect(net);
287
 
        
 
326
 
288
327
        if (net->host)
289
328
                ggz_free(net->host);
290
329
 
291
330
        /* Clear elements off stack and free it */
292
331
        if (net->stack) {
293
 
                while ( (element = ggz_stack_pop(net->stack))) 
 
332
                while ((element = ggz_stack_pop(net->stack)))
294
333
                        ggz_xmlelement_free(element);
295
334
                ggz_stack_free(net->stack);
296
335
        }
303
342
 
304
343
 
305
344
/* FIXME: set a timeout for connecting */
306
 
int _ggzcore_net_connect(GGZNet *net)
 
345
int _ggzcore_net_connect(GGZNet * net)
307
346
{
308
347
        ggz_debug(GGZCORE_DBG_NET, "Connecting to %s:%d",
309
348
                  net->host, net->port);
310
349
        net->fd = ggz_make_socket(GGZ_SOCK_CLIENT, net->port, net->host);
311
 
        
 
350
 
312
351
        if (net->fd >= 0)
313
 
                return 0;  /* success */
 
352
                return 0;       /* success */
314
353
        else
315
 
                return net->fd; /* error */
 
354
                return net->fd; /* error */
316
355
}
317
356
 
318
357
 
319
 
void _ggzcore_net_disconnect(GGZNet *net)
 
358
void _ggzcore_net_disconnect(GGZNet * net)
320
359
{
321
360
        ggz_debug(GGZCORE_DBG_NET, "Disconnecting");
 
361
#ifdef HAVE_WINSOCK2_H
 
362
        closesocket(net->fd);
 
363
#else
322
364
        close(net->fd);
 
365
#endif
323
366
        net->fd = -1;
324
367
}
325
368
 
326
369
 
 
370
/* Helper function, might go into libggz*/
 
371
char *_ggz_xml_cdata_escape(const char *str)
 
372
{
 
373
        char *new, *q;
 
374
        const char *p;
 
375
        size_t len = 0;
 
376
 
 
377
        if(str == NULL)
 
378
                return NULL;
 
379
 
 
380
        len = strlen(str);
 
381
 
 
382
        for(p = str; *p != '\0'; p++) {
 
383
                if((*p == ']') && (*(p + 1) == ']') && (*(p + 2) == '>')) {
 
384
                        len += 3;
 
385
                }
 
386
        }
 
387
 
 
388
        if(len == strlen(str))
 
389
                return ggz_strdup(str);
 
390
 
 
391
        q = new = ggz_malloc(len + 1);
 
392
        for(p = str; *p != '\0'; p++) {
 
393
                if((*p == ']') && (*(p + 1) == ']') && (*(p + 2) == '>')) {
 
394
                        memcpy(q, "]]&gt;", 6);
 
395
                        q += 6;
 
396
                        p += 2;
 
397
                } else {
 
398
                        *q = *p;
 
399
                        q++;
 
400
                }
 
401
        }
 
402
        *q = '\0';
 
403
 
 
404
        return new;
 
405
}
 
406
 
 
407
 
 
408
/* Helper function, might go into libggz*/
 
409
char *_ggz_xml_cdata_unescape(const char *str)
 
410
{
 
411
        char *new, *q;
 
412
        const char *p;
 
413
        size_t len = 0;
 
414
 
 
415
        if(str == NULL)
 
416
                return NULL;
 
417
 
 
418
        len = strlen(str);
 
419
 
 
420
        for(p = str; *p != '\0'; p++) {
 
421
                if(!strncmp(p, "]]&gt;", 6)) {
 
422
                        p += 5;
 
423
                        len += 2;
 
424
                }
 
425
                len++;
 
426
        }
 
427
 
 
428
        if(len == strlen(str))
 
429
                return ggz_strdup(str);
 
430
 
 
431
        q = new = ggz_malloc(len + 1);
 
432
        for(p = str; *p != '\0'; p++) {
 
433
                if(!strncmp(p, "]]&gt;", 6)) {
 
434
                        *q++ = *p++;
 
435
                        *q++ = *p++;
 
436
                        *q = '>';
 
437
                        q++;
 
438
                        p += 3;
 
439
                } else {
 
440
                        *q = *p;
 
441
                        q++;
 
442
                }
 
443
        }
 
444
        *q = '\0';
 
445
 
 
446
        return new;
 
447
}
 
448
 
 
449
 
327
450
/* ggzcore_net_send_XXX() functions for sending messages to the server */
328
451
 
329
 
int _ggzcore_net_send_login(GGZNet *net)
 
452
/* Sends login packet.  Login type is an enumerated value.  Password is needed
 
453
 * only for registered logins. */
 
454
int _ggzcore_net_send_login(GGZNet * net, GGZLoginType login_type,
 
455
                            const char *handle, const char *password, const char *email,
 
456
                            const char *language)
330
457
{
331
 
        GGZLoginType login_type;
332
 
        char *type, *handle, *password, *language;
333
 
        int status = 0;
 
458
        const char *type = "guest";
 
459
        int status;
 
460
        char *handle_quoted;
 
461
        char *password_quoted;
 
462
        char *email_quoted;
334
463
 
335
 
        login_type = _ggzcore_server_get_type(net->server);
336
 
        handle = _ggzcore_server_get_handle(net->server);
337
 
        password = _ggzcore_server_get_password(net->server);
338
 
        
339
464
        switch (login_type) {
340
465
        case GGZ_LOGIN:
341
466
                type = "normal";
344
469
                type = "first";
345
470
                break;
346
471
        case GGZ_LOGIN_GUEST:
347
 
        default:
348
472
                type = "guest";
 
473
                break;
349
474
        }
350
475
 
351
 
        language = getenv("LANG");
 
476
        handle_quoted = _ggz_xml_cdata_escape(handle);
 
477
        password_quoted = _ggz_xml_cdata_escape(password);
 
478
        email_quoted = _ggz_xml_cdata_escape(email);
 
479
 
352
480
        _ggzcore_net_send_line(net, "<LANGUAGE>%s</LANGUAGE>", language);
353
 
        
354
481
        _ggzcore_net_send_line(net, "<LOGIN TYPE='%s'>", type);
355
 
        _ggzcore_net_send_line(net, "<NAME>%s</NAME>", handle);
356
 
 
357
 
        if (login_type == GGZ_LOGIN)
358
 
                _ggzcore_net_send_line(net, "<PASSWORD>%s</PASSWORD>", password);
359
 
        _ggzcore_net_send_line(net, "</LOGIN>");
 
482
        _ggzcore_net_send_line(net, "<NAME><![CDATA[%s]]></NAME>", handle_quoted);
 
483
 
 
484
        if ((login_type == GGZ_LOGIN || (login_type == GGZ_LOGIN_NEW)) && password)
 
485
                _ggzcore_net_send_line(net, "<PASSWORD><![CDATA[%s]]></PASSWORD>",
 
486
                                       password_quoted);
 
487
        if (login_type == GGZ_LOGIN_NEW && email)
 
488
                _ggzcore_net_send_line(net, "<EMAIL><![CDATA[%s]]></EMAIL>",
 
489
                                       email_quoted);
 
490
 
 
491
        status = _ggzcore_net_send_line(net, "</LOGIN>");
 
492
 
 
493
        if (handle_quoted)
 
494
                ggz_free(handle_quoted);
 
495
        if (password_quoted)
 
496
                ggz_free(password_quoted);
 
497
        if (email_quoted)
 
498
                ggz_free(email_quoted);
360
499
 
361
500
        if (status < 0)
362
501
                _ggzcore_net_error(net, "Sending login");
365
504
}
366
505
 
367
506
 
368
 
int _ggzcore_net_send_channel(GGZNet *net)
 
507
int _ggzcore_net_send_channel(GGZNet * net, const char *id)
369
508
{
370
 
        char *id;
371
509
        int status = 0;
372
 
 
373
 
        id = _ggzcore_server_get_handle(net->server);
374
 
        
375
 
        status = _ggzcore_net_send_line(net, "<CHANNEL ID='%s' />", id);
 
510
        char *id_quoted;
 
511
 
 
512
        id_quoted = ggz_xml_escape(id);
 
513
 
 
514
        status = _ggzcore_net_send_line(net, "<CHANNEL ID='%s' />", id_quoted);
 
515
 
 
516
        ggz_free(id_quoted);
 
517
 
376
518
        if (status < 0)
377
519
                _ggzcore_net_error(net, "Sending channel");
378
520
 
380
522
}
381
523
 
382
524
 
383
 
int _ggzcore_net_send_motd(GGZNet *net)
 
525
int _ggzcore_net_send_motd(GGZNet * net)
384
526
{
385
527
        int status = 0;
386
528
 
387
 
        ggz_debug(GGZCORE_DBG_NET, "Sending MOTD request");     
 
529
        ggz_debug(GGZCORE_DBG_NET, "Sending MOTD request");
388
530
        _ggzcore_net_send_line(net, "<MOTD/>");
389
531
 
390
532
        return status;
391
533
}
392
534
 
393
535
 
394
 
int _ggzcore_net_send_list_types(GGZNet *net, const char verbose)
 
536
int _ggzcore_net_send_list_types(GGZNet * net, const char verbose)
395
537
{
396
538
        int status = 0;
397
539
        char *full;
398
540
 
399
541
        net->gametype_verbose = verbose;
400
542
 
401
 
        ggz_debug(GGZCORE_DBG_NET, "Sending gametype list request");    
 
543
        ggz_debug(GGZCORE_DBG_NET, "Sending gametype list request");
402
544
        full = bool_to_str(verbose);
403
 
        
 
545
 
404
546
        _ggzcore_net_send_line(net, "<LIST TYPE='game' FULL='%s'/>", full);
405
547
 
406
548
        return status;
407
549
}
408
550
 
409
551
 
410
 
int _ggzcore_net_send_list_rooms(GGZNet *net, const int type, const char verbose)
411
 
{       
 
552
int _ggzcore_net_send_list_rooms(GGZNet * net, const int type,
 
553
                                 const char verbose)
 
554
{
412
555
        int status = 0;
413
556
        char *full;
414
 
        
 
557
 
415
558
        net->room_verbose = verbose;
416
 
        ggz_debug(GGZCORE_DBG_NET, "Sending room list request");        
 
559
        ggz_debug(GGZCORE_DBG_NET, "Sending room list request");
417
560
        full = bool_to_str(verbose);
418
 
        
 
561
 
419
562
        _ggzcore_net_send_line(net, "<LIST TYPE='room' FULL='%s'/>", full);
420
563
 
421
564
        return status;
422
565
}
423
566
 
424
567
 
425
 
int _ggzcore_net_send_join_room(GGZNet *net, const unsigned int id)
 
568
int _ggzcore_net_send_join_room(GGZNet * net, const unsigned int room_id)
426
569
{
427
 
        int status = 0;
428
 
        GGZRoom *room;
429
 
 
430
 
        room = _ggzcore_server_get_room_by_id(net->server, id);
431
 
        net->new_room = room;
432
 
        
433
 
        ggz_debug(GGZCORE_DBG_NET, "Sending room join request");        
434
 
 
435
 
        _ggzcore_net_send_line(net, "<ENTER ROOM='%d'/>", id);
436
 
        
437
 
        return status;
 
570
        ggz_debug(GGZCORE_DBG_NET, "Sending room %d join request",
 
571
                  room_id);
 
572
        return _ggzcore_net_send_line(net, "<ENTER ROOM='%d'/>", room_id);
438
573
}
439
574
 
440
575
 
441
 
int _ggzcore_net_send_list_players(GGZNet *net)
442
 
{       
 
576
int _ggzcore_net_send_list_players(GGZNet * net)
 
577
{
443
578
        int status = 0;
444
579
 
445
580
        ggz_debug(GGZCORE_DBG_NET, "Sending player list request");
449
584
}
450
585
 
451
586
 
452
 
int _ggzcore_net_send_list_tables(GGZNet *net, const int type, const char global)
453
 
{       
 
587
int _ggzcore_net_send_list_tables(GGZNet * net, const int type,
 
588
                                  const char global)
 
589
{
454
590
        int status = 0;
455
591
 
456
592
        ggz_debug(GGZCORE_DBG_NET, "Sending table list request");
457
593
        _ggzcore_net_send_line(net, "<LIST TYPE='table'/>");
458
 
        
 
594
 
459
595
        return status;
460
596
}
461
597
 
462
598
/* Send a <CHAT> tag. */
463
 
int _ggzcore_net_send_chat(GGZNet *net, const GGZChatType type,
464
 
                           const char* player, const char* msg)
 
599
int _ggzcore_net_send_chat(GGZNet * net, const GGZChatType type,
 
600
                           const char *player, const char *msg)
465
601
{
466
602
        const char *type_str;
467
603
        const char *chat_text;
 
604
        char *chat_text_quoted;
468
605
        char *my_text = NULL;
469
606
        int result;
470
607
 
471
 
        ggz_debug(GGZCORE_DBG_NET, "Sending chat");     
 
608
        ggz_debug(GGZCORE_DBG_NET, "Sending chat");
472
609
 
473
610
        type_str = ggz_chattype_to_string(type);
474
611
 
490
627
                chat_text = msg;
491
628
        }
492
629
 
 
630
        chat_text_quoted = _ggz_xml_cdata_escape(chat_text);
 
631
 
493
632
        switch (type) {
494
633
        case GGZ_CHAT_NORMAL:
495
634
        case GGZ_CHAT_ANNOUNCE:
496
635
        case GGZ_CHAT_TABLE:
497
636
                result = _ggzcore_net_send_line(net,
498
 
                        "<CHAT TYPE='%s'><![CDATA[%s]]></CHAT>",
499
 
                        type_str, chat_text);
 
637
                                                "<CHAT TYPE='%s'><![CDATA[%s]]></CHAT>",
 
638
                                                type_str, chat_text_quoted);
500
639
                break;
501
640
        case GGZ_CHAT_BEEP:
502
641
                result = _ggzcore_net_send_line(net,
503
 
                        "<CHAT TYPE='%s' TO='%s'/>",
504
 
                        type_str, player);
 
642
                                                "<CHAT TYPE='%s' TO='%s'/>",
 
643
                                                type_str, player);
505
644
                break;
506
645
        case GGZ_CHAT_PERSONAL:
507
646
                result = _ggzcore_net_send_line(net,
508
 
                        "<CHAT TYPE='%s' TO='%s'><![CDATA[%s]]></CHAT>",
509
 
                        type_str, player, chat_text);
 
647
                                                "<CHAT TYPE='%s' TO='%s'><![CDATA[%s]]></CHAT>",
 
648
                                                type_str, player,
 
649
                                                chat_text_quoted);
510
650
                break;
511
651
        case GGZ_CHAT_UNKNOWN:
512
652
        default:
517
657
                break;
518
658
        }
519
659
 
 
660
        if (chat_text_quoted)
 
661
                ggz_free(chat_text_quoted);
 
662
 
520
663
        /*ggz_error_msg("ggzcore_net_send_chat: "
521
 
                      "unknown chat type given.");*/
 
664
           "unknown chat type given."); */
522
665
 
523
666
        if (my_text) {
524
667
                ggz_free(my_text);
528
671
}
529
672
 
530
673
 
531
 
int _ggzcore_net_send_table_launch(GGZNet *net, GGZTable *table)
 
674
int _ggzcore_net_send_player_info(GGZNet * net, int seat_num)
 
675
{
 
676
        int result;
 
677
 
 
678
        ggz_debug(GGZCORE_DBG_NET, "Sending player info request");
 
679
 
 
680
        if (seat_num == -1) {
 
681
                result = _ggzcore_net_send_line(net,
 
682
                        "<INFO/>");
 
683
        } else {
 
684
                result = _ggzcore_net_send_line(net,
 
685
                        "<INFO SEAT='%d'/>",
 
686
                        seat_num);
 
687
        }
 
688
 
 
689
        return result;
 
690
}
 
691
 
 
692
 
 
693
int _ggzcore_net_send_table_launch(GGZNet * net, GGZTable * table)
532
694
{
533
695
        int i, type, num_seats, status = 0;
534
 
        const char * desc;
535
 
        
 
696
        const char *desc;
 
697
        char *desc_quoted;
 
698
 
536
699
        ggz_debug(GGZCORE_DBG_NET, "Sending table launch request");
537
 
                
538
 
        type = _ggzcore_gametype_get_id(_ggzcore_table_get_type(table));
539
 
        desc = _ggzcore_table_get_desc(table);
540
 
        num_seats = _ggzcore_table_get_num_seats(table);
 
700
 
 
701
        type = ggzcore_gametype_get_id(ggzcore_table_get_type(table));
 
702
        desc = ggzcore_table_get_desc(table);
 
703
        num_seats = ggzcore_table_get_num_seats(table);
541
704
 
542
705
        _ggzcore_net_send_line(net, "<LAUNCH>");
543
 
        _ggzcore_net_send_line(net, "<TABLE GAME='%d' SEATS='%d'>", type, num_seats);
 
706
        _ggzcore_net_send_line(net, "<TABLE GAME='%d' SEATS='%d'>", type,
 
707
                               num_seats);
 
708
 
 
709
        desc_quoted = ggz_xml_escape(desc);
 
710
 
544
711
        if (desc)
545
 
                _ggzcore_net_send_line(net, "<DESC>%s</DESC>", desc);
546
 
        
547
 
        for (i = 0; i < num_seats; i++)
548
 
                _ggzcore_net_send_table_seat(net, _ggzcore_table_get_nth_seat(table, i));
549
 
        
 
712
                _ggzcore_net_send_line(net, "<DESC>%s</DESC>", desc_quoted);
 
713
 
 
714
        if (desc_quoted)
 
715
                ggz_free(desc_quoted);
 
716
 
 
717
        for (i = 0; i < num_seats; i++) {
 
718
                GGZTableSeat seat = _ggzcore_table_get_nth_seat(table, i);
 
719
 
 
720
                _ggzcore_net_send_table_seat(net, &seat);
 
721
        }
 
722
 
550
723
        _ggzcore_net_send_line(net, "</TABLE>");
551
724
        _ggzcore_net_send_line(net, "</LAUNCH>");
552
725
 
554
727
}
555
728
 
556
729
 
557
 
static int _ggzcore_net_send_table_seat(GGZNet *net,
558
 
                                        struct _GGZSeat *seat)
 
730
static int _ggzcore_net_send_table_seat(GGZNet * net, GGZTableSeat * seat)
559
731
{
560
732
        const char *type;
561
733
 
562
734
        ggz_debug(GGZCORE_DBG_NET, "Sending seat info");
563
 
        
 
735
 
564
736
        type = ggz_seattype_to_string(seat->type);
565
 
        
 
737
 
566
738
        if (!seat->name)
567
739
                return _ggzcore_net_send_line(net,
568
 
                                              "<SEAT NUM='%d' TYPE='%s'/>", 
 
740
                                              "<SEAT NUM='%d' TYPE='%s'/>",
569
741
                                              seat->index, type);
570
 
        return _ggzcore_net_send_line(net, 
571
 
                                      "<SEAT NUM='%d' TYPE='%s'>%s</SEAT>", 
572
 
                                      seat->index,type, seat->name);
 
742
        return _ggzcore_net_send_line(net,
 
743
                                      "<SEAT NUM='%d' TYPE='%s'>%s</SEAT>",
 
744
                                      seat->index, type, seat->name);
573
745
}
574
746
 
575
747
 
576
 
int _ggzcore_net_send_table_join(GGZNet *net,
577
 
                                 const unsigned int num,
578
 
                                 int spectator)
 
748
int _ggzcore_net_send_table_join(GGZNet * net,
 
749
                                 const unsigned int num, int spectator)
579
750
{
580
751
        ggz_debug(GGZCORE_DBG_NET, "Sending table join request");
581
 
        return _ggzcore_net_send_line(net, "<JOIN TABLE='%d' SPECTATOR='%s'/>",
 
752
        return _ggzcore_net_send_line(net,
 
753
                                      "<JOIN TABLE='%d' SPECTATOR='%s'/>",
582
754
                                      num, bool_to_str(spectator));
583
755
}
584
756
 
585
 
int _ggzcore_net_send_table_leave(GGZNet *net,
586
 
                                  int force,
587
 
                                  int spectator)
 
757
int _ggzcore_net_send_table_leave(GGZNet * net, int force, int spectator)
588
758
{
589
759
        ggz_debug(GGZCORE_DBG_NET, "Sending table leave request");
590
760
        return _ggzcore_net_send_line(net,
594
764
}
595
765
 
596
766
 
597
 
int _ggzcore_net_send_table_reseat(GGZNet *net,
598
 
                                   GGZReseatType opcode,
599
 
                                   int seat_num)
 
767
int _ggzcore_net_send_table_reseat(GGZNet * net,
 
768
                                   GGZReseatType opcode, int seat_num)
600
769
{
601
770
        const char *action = NULL;
602
771
 
615
784
                break;
616
785
        }
617
786
 
618
 
        if (!action) return -1;
 
787
        if (!action)
 
788
                return -1;
619
789
 
620
790
        if (seat_num < 0)
621
791
                return _ggzcore_net_send_line(net,
628
798
}
629
799
 
630
800
 
631
 
int _ggzcore_net_send_table_seat_update(GGZNet *net, GGZTable *table,
632
 
                                        struct _GGZSeat *seat)
 
801
int _ggzcore_net_send_table_seat_update(GGZNet * net, GGZTable * table,
 
802
                                        GGZTableSeat * seat)
633
803
{
 
804
        const GGZRoom *room = ggzcore_table_get_room(table);
 
805
        int room_id = ggzcore_room_get_id(room);
 
806
        int id = ggzcore_table_get_id(table);
 
807
        int num_seats = ggzcore_table_get_num_seats(table);
 
808
 
634
809
        ggz_debug(GGZCORE_DBG_NET, "Sending table seat update request");
635
810
        _ggzcore_net_send_line(net,
636
811
                               "<UPDATE TYPE='table' ACTION='seat' ROOM='%d'>",
637
 
                               _ggzcore_room_get_id(table->room));
 
812
                               room_id);
638
813
        _ggzcore_net_send_line(net, "<TABLE ID='%d' SEATS='%d'>",
639
 
                               table->id, table->num_seats);
 
814
                               id, num_seats);
640
815
        _ggzcore_net_send_table_seat(net, seat);
641
816
        _ggzcore_net_send_line(net, "</TABLE>");
642
817
        return _ggzcore_net_send_line(net, "</UPDATE>");
644
819
 
645
820
 
646
821
 
647
 
int _ggzcore_net_send_table_desc_update(GGZNet *net, GGZTable *table,
 
822
int _ggzcore_net_send_table_desc_update(GGZNet * net, GGZTable * table,
648
823
                                        const char *desc)
649
824
{
650
 
        ggz_debug(GGZCORE_DBG_NET, "Sending table description update request");
 
825
        const GGZRoom *room = ggzcore_table_get_room(table);
 
826
        int room_id = ggzcore_room_get_id(room);
 
827
        int id = ggzcore_table_get_id(table);
 
828
        char *desc_quoted;
 
829
 
 
830
        ggz_debug(GGZCORE_DBG_NET,
 
831
                  "Sending table description update request");
651
832
        _ggzcore_net_send_line(net,
652
833
                               "<UPDATE TYPE='table' ACTION='desc' ROOM='%d'>",
653
 
                               _ggzcore_room_get_id(table->room));
654
 
        _ggzcore_net_send_line(net, "<TABLE ID='%d'>", table->id);
655
 
        _ggzcore_net_send_line(net, "<DESC>%s</DESC>", desc);
 
834
                               room_id);
 
835
 
 
836
        desc_quoted = ggz_xml_escape(desc);
 
837
 
 
838
        _ggzcore_net_send_line(net, "<TABLE ID='%d'>", id);
 
839
        _ggzcore_net_send_line(net, "<DESC>%s</DESC>", desc_quoted);
656
840
        _ggzcore_net_send_line(net, "</TABLE>");
657
 
        return _ggzcore_net_send_line(net, "</UPDATE>");        
 
841
 
 
842
        ggz_free(desc_quoted);
 
843
 
 
844
        return _ggzcore_net_send_line(net, "</UPDATE>");
658
845
}
659
846
 
660
847
 
661
 
int _ggzcore_net_send_table_boot_update(GGZNet *net, GGZTable *table,
662
 
                                        struct _GGZSeat *seat)
 
848
int _ggzcore_net_send_table_boot_update(GGZNet * net, GGZTable * table,
 
849
                                        GGZTableSeat * seat)
663
850
{
664
 
        ggz_debug(GGZCORE_DBG_NET, "Sending boot of player %s.", seat->name);
 
851
        const GGZRoom *room = ggzcore_table_get_room(table);
 
852
        int room_id = ggzcore_room_get_id(room);
 
853
        int id = ggzcore_table_get_id(table);
 
854
 
 
855
        ggz_debug(GGZCORE_DBG_NET, "Sending boot of player %s.",
 
856
                  seat->name);
665
857
 
666
858
        if (!seat->name)
667
859
                return -1;
670
862
 
671
863
        _ggzcore_net_send_line(net,
672
864
                               "<UPDATE TYPE='table' ACTION='boot' ROOM='%d'>",
673
 
                               _ggzcore_room_get_id(table->room));
 
865
                               room_id);
674
866
 
675
 
        _ggzcore_net_send_line(net, "<TABLE ID='%d' SEATS='1'>", table->id);
 
867
        _ggzcore_net_send_line(net, "<TABLE ID='%d' SEATS='1'>", id);
676
868
        _ggzcore_net_send_table_seat(net, seat);
677
869
        _ggzcore_net_send_line(net, "</TABLE>");
678
870
 
680
872
}
681
873
 
682
874
 
683
 
int _ggzcore_net_send_logout(GGZNet *net)
 
875
int _ggzcore_net_send_logout(GGZNet * net)
684
876
{
685
 
        ggz_debug(GGZCORE_DBG_NET, "Sending LOGOUT");   
 
877
        ggz_debug(GGZCORE_DBG_NET, "Sending LOGOUT");
686
878
        return _ggzcore_net_send_line(net, "</SESSION>");
687
879
}
688
880
 
689
881
 
690
882
/* Check for incoming data */
691
 
int _ggzcore_net_data_is_pending(GGZNet *net)
 
883
int _ggzcore_net_data_is_pending(GGZNet * net)
692
884
{
693
 
        int pending = 0;
694
 
        struct pollfd fd[1] = {{net->fd, POLLIN, 0}};
695
 
 
696
885
        if (net && net->fd >= 0) {
697
 
        
698
 
                ggz_debug(GGZCORE_DBG_POLL, "Checking for net events"); 
699
 
                if ( (pending = poll(fd, 1, 0)) < 0) {
700
 
                        if (errno == EINTR) 
 
886
                fd_set read_fd_set;
 
887
                int result;
 
888
                struct timeval tv;
 
889
 
 
890
                FD_ZERO(&read_fd_set);
 
891
                FD_SET(net->fd, &read_fd_set);
 
892
 
 
893
                tv.tv_sec = tv.tv_usec = 0;
 
894
 
 
895
                ggz_debug(GGZCORE_DBG_POLL, "Checking for net events");
 
896
                result =
 
897
                    select(net->fd + 1, &read_fd_set, NULL, NULL, &tv);
 
898
                if (result < 0) {
 
899
                        if (errno == EINTR)
701
900
                                /* Ignore interruptions */
702
 
                                pending = 0;
703
 
                        else 
704
 
                                ggz_error_sys_exit("poll failed in ggzcore_server_data_is_pending");
705
 
                }
706
 
                else if (pending)
 
901
                                return 0;
 
902
                        else
 
903
                                ggz_error_sys_exit
 
904
                                    ("select failed in ggzcore_server_data_is_pending");
 
905
                } else if (result > 0) {
707
906
                        ggz_debug(GGZCORE_DBG_POLL, "Found a net event!");
 
907
                        return 1;
 
908
                }
708
909
        }
709
910
 
710
 
        return pending;
 
911
        return 0;
711
912
}
712
913
 
713
914
 
714
 
/* Read in a bit more from the server and send it to the parser */
715
 
int _ggzcore_net_read_data(GGZNet *net)
 
915
/* Read in a bit more from the server and send it to the parser.  The return
 
916
 * value seems to mean nothing (???). */
 
917
int _ggzcore_net_read_data(GGZNet * net)
716
918
{
717
919
        char *buf;
718
920
        int len, done;
719
921
 
720
922
        /* We're already in a parse call, and XML parsing is *not* reentrant */
721
 
        if (net->parsing) 
 
923
        if (net->parsing)
722
924
                return 0;
723
925
 
724
926
        /* Set flag in case we get called recursively */
729
931
                ggz_error_sys_exit("Couldn't allocate buffer");
730
932
 
731
933
        /* Read in data from socket */
732
 
        if ( (len = ggz_tls_read(net->fd, buf, XML_BUFFSIZE)) < 0) {
733
 
                
 
934
        if ((len = ggz_tls_read(net->fd, buf, XML_BUFFSIZE)) < 0) {
 
935
 
734
936
                /* If it's a non-blocking socket and there isn't data,
735
 
                   we get EAGAIN.  It's safe to just return */
 
937
                   we get EAGAIN.  It's safe to just return */
736
938
                if (errno == EAGAIN) {
737
939
                        net->parsing = 0;
738
940
                        return 0;
741
943
        }
742
944
 
743
945
        _ggzcore_net_dump_data(net, buf, len);
744
 
        
 
946
 
745
947
        /* If len == 0 then we've reached EOF */
746
948
        done = (len == 0);
747
949
        if (done) {
748
 
                _ggzcore_server_protocol_error(net->server, "Server disconnected");
 
950
                _ggzcore_server_protocol_error(net->server,
 
951
                                               "Server disconnected");
749
952
                _ggzcore_net_disconnect(net);
750
953
                _ggzcore_server_session_over(net->server, net);
751
 
        }
752
 
        else if (!XML_ParseBuffer(net->parser, len, done)) {
753
 
                ggz_debug(GGZCORE_DBG_XML, "Parse error at line %d, col %d:%s",
 
954
        } else if (!XML_ParseBuffer(net->parser, len, done)) {
 
955
                ggz_debug(GGZCORE_DBG_XML,
 
956
                          "Parse error at line %d, col %d:%s",
754
957
                          XML_GetCurrentLineNumber(net->parser),
755
958
                          XML_GetCurrentColumnNumber(net->parser),
756
959
                          XML_ErrorString(XML_GetErrorCode(net->parser)));
757
 
                _ggzcore_server_protocol_error(net->server, "Bad XML from server");
 
960
                _ggzcore_server_protocol_error(net->server,
 
961
                                               "Bad XML from server");
758
962
        }
759
 
        
 
963
 
760
964
        /* Clear the flag now that we're done */
761
965
        net->parsing = 0;
762
966
        return done;
764
968
 
765
969
 
766
970
/********** Callbacks for XML parser **********/
767
 
static void _ggzcore_net_parse_start_tag(void *data, const char *el, const char **attr)
 
971
static void _ggzcore_net_parse_start_tag(void *data, const char *el,
 
972
                                         const char **attr)
768
973
{
769
974
        GGZNet *net = data;
770
975
        GGZStack *stack = net->stack;
771
976
        GGZXMLElement *element;
772
977
 
773
978
        ggz_debug(GGZCORE_DBG_XML, "New %s element", el);
774
 
        
 
979
 
775
980
        /* Create new element object */
776
 
        element = _ggzcore_net_new_element((char*)el, (char**)attr);
 
981
        element = _ggzcore_net_new_element(el, attr);
777
982
 
778
983
        /* Put element on stack so we can process its children */
779
984
        ggz_stack_push(stack, element);
789
994
        element = ggz_stack_pop(net->stack);
790
995
 
791
996
        /* Process tag */
792
 
        ggz_debug(GGZCORE_DBG_XML, "Handling %s element", 
 
997
        ggz_debug(GGZCORE_DBG_XML, "Handling %s element",
793
998
                  ggz_xmlelement_get_tag(element));
794
999
 
795
1000
        if (element->process)
800
1005
}
801
1006
 
802
1007
 
803
 
static void _ggzcore_net_parse_text(void *data, const char *text, int len) 
 
1008
static void _ggzcore_net_parse_text(void *data, const char *text, int len)
804
1009
{
805
1010
        GGZNet *net = data;
806
1011
        GGZStack *stack = net->stack;
811
1016
}
812
1017
 
813
1018
 
814
 
static void _ggzcore_net_error(GGZNet *net, char* message)
 
1019
static void _ggzcore_net_error(GGZNet * net, char *message)
815
1020
{
816
1021
        ggz_debug(GGZCORE_DBG_NET, "Network error: %s", message);
817
1022
        _ggzcore_net_disconnect(net);
819
1024
}
820
1025
 
821
1026
 
822
 
static void _ggzcore_net_dump_data(GGZNet *net, char *data, int size)
 
1027
static void _ggzcore_net_dump_data(GGZNet * net, char *data, int size)
823
1028
{
824
 
        if (net->dump_file > 0)
825
 
                write(net->dump_file, data, size);
 
1029
        if (net->dump_file) {
 
1030
                fwrite(data, 1, size, net->dump_file);
 
1031
                fflush(net->dump_file);
 
1032
        }
826
1033
}
827
1034
 
828
 
static GGZXMLElement* _ggzcore_net_new_element(char *tag, char **attrs)
 
1035
static GGZXMLElement *_ggzcore_net_new_element(const char *tag,
 
1036
                                               const char *const *attrs)
829
1037
{
830
 
        void (*process_func)();
 
1038
        void (*process_func) ();
831
1039
 
832
1040
        /* FIXME: Could we do this with a table lookup? */
833
1041
        if (strcasecmp(tag, "SERVER") == 0)
850
1058
                process_func = _ggzcore_net_handle_allow;
851
1059
        else if (strcasecmp(tag, "ABOUT") == 0)
852
1060
                process_func = _ggzcore_net_handle_about;
 
1061
        else if (strcasecmp(tag, "BOT") == 0)
 
1062
                process_func = _ggzcore_net_handle_bot;
853
1063
        else if (strcasecmp(tag, "ROOM") == 0)
854
1064
                process_func = _ggzcore_net_handle_room;
855
1065
        else if (strcasecmp(tag, "PLAYER") == 0)
866
1076
                process_func = _ggzcore_net_handle_join;
867
1077
        else if (strcasecmp(tag, "CHAT") == 0)
868
1078
                process_func = _ggzcore_net_handle_chat;
 
1079
        else if (strcasecmp(tag, "INFO") == 0)
 
1080
                process_func = _ggzcore_net_handle_info;
 
1081
        else if (strcasecmp(tag, "PLAYERINFO") == 0)
 
1082
                process_func = _ggzcore_net_handle_playerinfo;
869
1083
        else if (strcasecmp(tag, "DESC") == 0)
870
1084
                process_func = _ggzcore_net_handle_desc;
871
1085
        else if (strcasecmp(tag, "PASSWORD") == 0)
876
1090
                process_func = _ggzcore_net_handle_session;
877
1091
        else
878
1092
                process_func = NULL;
879
 
        
 
1093
 
880
1094
        return ggz_xmlelement_new(tag, attrs, process_func, NULL);
881
1095
}
882
1096
 
883
1097
 
884
1098
/* Functions for <SERVER> tag */
885
 
void _ggzcore_net_handle_server(GGZNet *net, GGZXMLElement *element)
 
1099
void _ggzcore_net_handle_server(GGZNet * net, GGZXMLElement * element)
886
1100
{
887
 
        char *name, *id, *status, *tls;
 
1101
        const char *name, *id, *status, *tls;
888
1102
        int version;
889
1103
        int *chatlen;
890
1104
 
891
 
        if (!element) return;
 
1105
        if (!element)
 
1106
                return;
892
1107
 
893
1108
        name = ATTR(element, "NAME");
894
1109
        id = ATTR(element, "ID");
906
1121
                net->chat_size = chatlen ? *chatlen : UINT_MAX;
907
1122
        }
908
1123
 
909
 
        ggz_debug(GGZCORE_DBG_NET, 
 
1124
        ggz_debug(GGZCORE_DBG_NET,
910
1125
                  "%s(%s) : status %s: protocol %d: chat size %u tls: %s",
911
1126
                  name, id, status, version, net->chat_size, tls);
912
1127
 
916
1131
                _ggzcore_net_send_header(net);
917
1132
 
918
1133
                /* If TLS is enabled set it up */
919
 
                if(tls && !strcmp(tls, "yes") && _ggzcore_net_get_tls(net) == 1 && ggz_tls_support_query())
 
1134
                if (tls && !strcmp(tls, "yes")
 
1135
                    && _ggzcore_net_get_tls(net) == 1
 
1136
                    && ggz_tls_support_query())
920
1137
                        _ggzcore_net_negotiate_tls(net);
921
1138
 
922
1139
                _ggzcore_server_set_negotiate_status(net->server, net,
927
1144
 
928
1145
 
929
1146
/* Functions for <OPTIONS> tag */
930
 
static void _ggzcore_net_handle_options(GGZNet *net, GGZXMLElement *element)
 
1147
static void _ggzcore_net_handle_options(GGZNet * net,
 
1148
                                        GGZXMLElement * element)
931
1149
{
932
1150
        int *len, chatlen;
933
1151
        GGZXMLElement *parent;
934
1152
        const char *parent_tag;
935
1153
 
936
 
        if (!element) return;
 
1154
        if (!element)
 
1155
                return;
937
1156
 
938
1157
        /* Get parent off top of stack */
939
1158
        parent = ggz_stack_top(net->stack);
940
1159
        if (!parent)
941
 
                return; /* should this be an error? */
 
1160
                return; /* should this be an error? */
942
1161
        parent_tag = ggz_xmlelement_get_tag(parent);
943
1162
        if (strcasecmp(parent_tag, "SERVER") != 0)
944
 
                return; /* should this be an error? */
 
1163
                return; /* should this be an error? */
945
1164
 
946
1165
        /* Read the server's maximum chat length. */
947
1166
        chatlen = str_to_int(ATTR(element, "CHATLEN"), -1);
948
 
        if (chatlen < 0) return;
 
1167
        if (chatlen < 0)
 
1168
                return;
949
1169
 
950
1170
        len = ggz_malloc(sizeof(*len));
951
1171
        *len = chatlen;
954
1174
 
955
1175
 
956
1176
/* Functions for <MOTD> tag */
957
 
static void _ggzcore_net_handle_motd(GGZNet *net, GGZXMLElement *element)
 
1177
static void _ggzcore_net_handle_motd(GGZNet * net, GGZXMLElement * element)
958
1178
{
959
 
        char *message, *priority;
960
 
        char **buffer;
 
1179
        const char *message, *priority, *url;
 
1180
        GGZMotdEventData motd;
961
1181
 
962
1182
        message = ggz_xmlelement_get_text(element);
963
1183
        priority = ATTR(element, "PRIORITY");
964
 
        
 
1184
        url = ATTR(element, "URL");
 
1185
 
965
1186
        ggz_debug(GGZCORE_DBG_NET, "Motd of priority %s", priority);
966
1187
 
967
1188
        /* In the old interface the MOTD was sent a line at a time,
968
1189
           NULL-terminated.  Now it's just sent all at once. */
969
 
        buffer = ggz_malloc(2 * sizeof(char*));
970
 
        buffer[0] = message;
971
 
        buffer[1] = NULL;
 
1190
        if (url && strlen(url) == 0) url = NULL;
 
1191
        motd.motd = message;
 
1192
        motd.url = url;
972
1193
 
973
1194
        /* FIXME: do something with the priority */
974
 
        _ggzcore_server_event(net->server, GGZ_MOTD_LOADED, buffer);
975
 
 
976
 
        ggz_free(buffer);
 
1195
        _ggzcore_server_event(net->server, GGZ_MOTD_LOADED, &motd);
977
1196
}
978
1197
 
979
1198
 
980
1199
/* Functions for <RESULT> tag */
981
 
static void _ggzcore_net_handle_result(GGZNet *net, GGZXMLElement *element)
 
1200
static void _ggzcore_net_handle_result(GGZNet * net,
 
1201
                                       GGZXMLElement * element)
982
1202
{
983
1203
        GGZRoom *room;
984
 
        char *action;
 
1204
        const char *action;
985
1205
        GGZClientReqError code;
986
1206
        void *data;
987
1207
        char *message;
988
1208
 
989
 
        if (!element) return;
 
1209
        if (!element)
 
1210
                return;
990
1211
 
991
1212
        action = ATTR(element, "ACTION");
992
1213
        code = ggz_string_to_error(ATTR(element, "CODE"));
993
1214
        data = ggz_xmlelement_get_data(element);
994
1215
 
995
 
        ggz_debug(GGZCORE_DBG_NET, "Result of %s was %d", action, 
996
 
                  code);
 
1216
        ggz_debug(GGZCORE_DBG_NET, "Result of %s was %d", action, code);
997
1217
 
998
1218
        room = _ggzcore_server_get_cur_room(net->server);
999
1219
 
1001
1221
                /* Password may have already been updated. */
1002
1222
                _ggzcore_server_set_login_status(net->server, code);
1003
1223
        } else if (strcasecmp(action, "enter") == 0) {
1004
 
                if (code == E_OK)
1005
 
                        _ggzcore_server_set_room(net->server, net->new_room);
1006
1224
                _ggzcore_server_set_room_join_status(net->server, code);
1007
 
        } else if  (strcasecmp(action, "launch") == 0)
 
1225
        } else if (strcasecmp(action, "launch") == 0)
1008
1226
                _ggzcore_room_set_table_launch_status(room, code);
1009
 
        else if  (strcasecmp(action, "join") == 0)
 
1227
        else if (strcasecmp(action, "join") == 0)
1010
1228
                _ggzcore_room_set_table_join_status(room, code);
1011
 
        else if  (strcasecmp(action, "leave") == 0)
 
1229
        else if (strcasecmp(action, "leave") == 0)
1012
1230
                _ggzcore_room_set_table_leave_status(room, code);
1013
 
        else if  (strcasecmp(action, "chat") == 0) {
 
1231
        else if (strcasecmp(action, "chat") == 0) {
1014
1232
                if (code != E_OK) {
1015
 
                        GGZErrorEventData error = {status: code};
 
1233
                      GGZErrorEventData error = { status:code };
1016
1234
 
1017
1235
                        switch (code) {
1018
1236
                        case E_NOT_IN_ROOM:
1019
 
                                snprintf(error.message, sizeof(error.message),
 
1237
                                snprintf(error.message,
 
1238
                                         sizeof(error.message),
1020
1239
                                         "Not in a room");
1021
1240
                                break;
1022
1241
                        case E_BAD_OPTIONS:
1023
 
                                snprintf(error.message, sizeof(error.message),
 
1242
                                snprintf(error.message,
 
1243
                                         sizeof(error.message),
1024
1244
                                         "Bad options");
1025
1245
                                break;
1026
1246
                        case E_NO_PERMISSION:
1027
 
                                snprintf(error.message, sizeof(error.message),
 
1247
                                snprintf(error.message,
 
1248
                                         sizeof(error.message),
1028
1249
                                         "Prohibited");
1029
1250
                                break;
1030
1251
                        case E_USR_LOOKUP:
1031
 
                                snprintf(error.message, sizeof(error.message),
 
1252
                                snprintf(error.message,
 
1253
                                         sizeof(error.message),
1032
1254
                                         "No such player");
1033
1255
                                break;
1034
1256
                        case E_AT_TABLE:
1035
 
                                snprintf(error.message, sizeof(error.message),
 
1257
                                snprintf(error.message,
 
1258
                                         sizeof(error.message),
1036
1259
                                         "Can't chat at table");
1037
1260
                                break;
 
1261
                        case E_NO_TABLE:
 
1262
                                snprintf(error.message,
 
1263
                                         sizeof(error.message),
 
1264
                                         "Must be at table");
 
1265
                                break;
1038
1266
                        default:
1039
 
                                snprintf(error.message, sizeof(error.message),
 
1267
                                snprintf(error.message,
 
1268
                                         sizeof(error.message),
1040
1269
                                         "Unknown error");
1041
1270
                                break;
1042
1271
                        }
1047
1276
                /* These are always errors */
1048
1277
                switch (code) {
1049
1278
                case E_BAD_OPTIONS:
1050
 
                        message = "Server didn't recognize one of our commands";
 
1279
                        message =
 
1280
                            "Server didn't recognize one of our commands";
1051
1281
                        break;
1052
1282
                case E_BAD_XML:
1053
1283
                        message = "Server didn't like our XML";
1055
1285
                default:
1056
1286
                        message = "Unknown protocol error";
1057
1287
                }
1058
 
                
 
1288
 
1059
1289
                _ggzcore_server_protocol_error(net->server, message);
1060
1290
        }
1061
1291
 
1064
1294
 
1065
1295
 
1066
1296
/* Functions for <PASSWORD> tag */
1067
 
static void _ggzcore_net_handle_password(GGZNet *net, GGZXMLElement *element)
 
1297
static void _ggzcore_net_handle_password(GGZNet * net,
 
1298
                                         GGZXMLElement * element)
1068
1299
{
1069
1300
        char *password;
1070
1301
        GGZXMLElement *parent;
1091
1322
 
1092
1323
 
1093
1324
/* Functions for <LIST> tag */
1094
 
static void _ggzcore_net_handle_list(GGZNet *net, GGZXMLElement *element)
 
1325
static void _ggzcore_net_handle_list(GGZNet * net, GGZXMLElement * element)
1095
1326
{
1096
1327
        GGZList *list;
1097
1328
        GGZListEntry *entry;
1098
1329
        GGZRoom *room;
1099
1330
        int count, room_num;
1100
 
        char *type;
 
1331
        const char *type;
1101
1332
 
1102
1333
        if (!element)
1103
1334
                return;
1111
1342
        /* FIXME: we should be able to get this from the list itself */
1112
1343
        count = 0;
1113
1344
        for (entry = ggz_list_head(list);
1114
 
             entry;
1115
 
             entry = ggz_list_next(entry))
 
1345
             entry; entry = ggz_list_next(entry))
1116
1346
                count++;
1117
1347
 
1118
1348
        if (strcasecmp(type, "room") == 0) {
1123
1353
                _ggzcore_server_init_roomlist(net->server, count);
1124
1354
 
1125
1355
                for (entry = ggz_list_head(list);
1126
 
                     entry;
1127
 
                     entry = ggz_list_next(entry)) {
 
1356
                     entry; entry = ggz_list_next(entry)) {
1128
1357
                        _ggzcore_server_add_room(net->server,
1129
1358
                                                 ggz_list_get_data(entry));
1130
1359
                }
1131
1360
                _ggzcore_server_event(net->server, GGZ_ROOM_LIST, NULL);
1132
1361
        } else if (strcasecmp(type, "game") == 0) {
1133
 
                /* Free previous list of types*/
 
1362
                /* Free previous list of types */
1134
1363
                if (ggzcore_server_get_num_gametypes(net->server) > 0)
1135
1364
                        _ggzcore_server_free_typelist(net->server);
1136
1365
 
1137
1366
                _ggzcore_server_init_typelist(net->server, count);
1138
1367
                for (entry = ggz_list_head(list);
1139
 
                     entry;
1140
 
                     entry = ggz_list_next(entry)) {
 
1368
                     entry; entry = ggz_list_next(entry)) {
1141
1369
                        _ggzcore_server_add_type(net->server,
1142
1370
                                                 ggz_list_get_data(entry));
1143
1371
                }
1144
1372
                _ggzcore_server_event(net->server, GGZ_TYPE_LIST, NULL);
1145
1373
        } else if (strcasecmp(type, "player") == 0) {
1146
 
                room = _ggzcore_server_get_room_by_id(net->server, room_num);
 
1374
                room =
 
1375
                    _ggzcore_server_get_room_by_id(net->server, room_num);
1147
1376
                _ggzcore_room_set_player_list(room, count, list);
1148
 
                list = NULL; /* avoid freeing list */
 
1377
                list = NULL;    /* avoid freeing list */
1149
1378
        } else if (strcasecmp(type, "table") == 0) {
1150
 
                room = _ggzcore_server_get_room_by_id(net->server, room_num);
 
1379
                room =
 
1380
                    _ggzcore_server_get_room_by_id(net->server, room_num);
1151
1381
                _ggzcore_room_set_table_list(room, count, list);
1152
 
                list = NULL; /* avoid freeing list */
 
1382
                list = NULL;    /* avoid freeing list */
1153
1383
        }
1154
1384
 
1155
1385
        if (list)
1157
1387
}
1158
1388
 
1159
1389
 
1160
 
static void _ggzcore_net_list_insert(GGZXMLElement *list_tag, void *data)
 
1390
static void _ggzcore_net_list_insert(GGZXMLElement * list_tag, void *data)
1161
1391
{
1162
1392
        GGZList *list = ggz_xmlelement_get_data(list_tag);
1163
 
        
 
1393
 
1164
1394
        /* If list doesn't already exist, create it */
1165
1395
        if (!list) {
1166
 
                /* Setup actual list */ 
1167
 
                char *type = ATTR(list_tag, "TYPE");
 
1396
                /* Setup actual list */
 
1397
                const char *type = ATTR(list_tag, "TYPE");
1168
1398
                ggzEntryCompare compare_func = NULL;
1169
 
                ggzEntryCreate  create_func = NULL;
 
1399
                ggzEntryCreate create_func = NULL;
1170
1400
                ggzEntryDestroy destroy_func = NULL;
1171
1401
 
1172
 
                if (strcasecmp(type, "game") == 0) {}
1173
 
                else if (strcasecmp(type, "room") == 0) {}
1174
 
                else if (strcasecmp(type, "player") == 0) {
 
1402
                if (strcasecmp(type, "game") == 0) {
 
1403
                } else if (strcasecmp(type, "room") == 0) {
 
1404
                } else if (strcasecmp(type, "player") == 0) {
1175
1405
                        compare_func = _ggzcore_player_compare;
1176
1406
                        destroy_func = _ggzcore_player_destroy;
1177
 
                }               
1178
 
                else if (strcasecmp(type, "table") == 0) {
 
1407
                } else if (strcasecmp(type, "table") == 0) {
1179
1408
                        compare_func = _ggzcore_table_compare;
1180
1409
                        destroy_func = _ggzcore_table_destroy;
1181
 
                }               
1182
 
                list = ggz_list_create(compare_func, 
1183
 
                                            create_func, 
1184
 
                                            destroy_func,
1185
 
                                            GGZ_LIST_ALLOW_DUPS);
1186
 
                
 
1410
                }
 
1411
                list = ggz_list_create(compare_func,
 
1412
                                       create_func,
 
1413
                                       destroy_func, GGZ_LIST_ALLOW_DUPS);
 
1414
 
1187
1415
                ggz_xmlelement_set_data(list_tag, list);
1188
1416
        }
1189
1417
 
1192
1420
 
1193
1421
 
1194
1422
/* Functions for <UPDATE> tag */
1195
 
static void _ggzcore_net_handle_update(GGZNet *net, GGZXMLElement *element)
 
1423
static void _ggzcore_net_handle_update(GGZNet * net,
 
1424
                                       GGZXMLElement * element)
1196
1425
{
1197
 
        char *action, *type;
 
1426
        const char *action, *type;
1198
1427
 
1199
1428
        /* Return if there's no tag */
1200
1429
        if (!element)
1201
1430
                return;
1202
 
        
 
1431
 
1203
1432
        /* Grab update data from tag */
1204
1433
        type = ATTR(element, "TYPE");
1205
1434
        action = ATTR(element, "ACTION");
1206
1435
 
1207
1436
        if (strcasecmp(type, "room") == 0) {
1208
 
                /* FIXME: implement this */
 
1437
                _ggzcore_net_room_update(net, element, action);
1209
1438
        } else if (strcasecmp(type, "game") == 0) {
1210
1439
                /* FIXME: implement this */
1211
1440
        } else if (strcasecmp(type, "player") == 0)
1215
1444
}
1216
1445
 
1217
1446
 
 
1447
/* Handle room update. */
 
1448
static void _ggzcore_net_room_update(GGZNet * net, GGZXMLElement * update,
 
1449
                                     const char *action)
 
1450
{
 
1451
        GGZRoom *roomdata, *room;
 
1452
        int id, players;
 
1453
 
 
1454
        roomdata = ggz_xmlelement_get_data(update);
 
1455
        if (!roomdata)
 
1456
                return;
 
1457
        id = ggzcore_room_get_id(roomdata);
 
1458
        room = _ggzcore_server_get_room_by_id(net->server, id);
 
1459
 
 
1460
        if (room) {
 
1461
                if (strcasecmp(action, "players") == 0) {
 
1462
                        players = ggzcore_room_get_num_players(roomdata);
 
1463
                        _ggzcore_room_set_players(room, players);
 
1464
                }
 
1465
        }
 
1466
 
 
1467
        _ggzcore_room_free(roomdata);
 
1468
}
 
1469
 
 
1470
 
1218
1471
/* Handle Player update */
1219
 
static void _ggzcore_net_player_update(GGZNet *net, GGZXMLElement *update,
1220
 
                                       char *action)
 
1472
static void _ggzcore_net_player_update(GGZNet * net,
 
1473
                                       GGZXMLElement * update,
 
1474
                                       const char *action)
1221
1475
{
1222
1476
        int room_num;
1223
1477
        GGZPlayer *player;
1224
1478
        GGZRoom *room;
 
1479
        const char *player_name;
1225
1480
 
1226
1481
        room_num = str_to_int(ATTR(update, "ROOM"), -1);
1227
1482
 
1228
1483
        player = ggz_xmlelement_get_data(update);
 
1484
        if (!player) {
 
1485
                return;
 
1486
        }
 
1487
        player_name = ggzcore_player_get_name(player);
 
1488
 
1229
1489
        room = _ggzcore_server_get_room_by_id(net->server, room_num);
1230
 
        
1231
 
        if (strcasecmp(action, "add") == 0)
1232
 
                _ggzcore_room_add_player(room, player);
1233
 
        else if (strcasecmp(action, "delete") == 0)
1234
 
                _ggzcore_room_remove_player(room, player->name);
1235
 
        else if (strcasecmp(action, "lag") == 0) {
 
1490
        if (!room) {
 
1491
                _ggzcore_player_free(player);
 
1492
                return;
 
1493
        }
 
1494
 
 
1495
 
 
1496
        if (strcasecmp(action, "add") == 0) {
 
1497
                int from_room = str_to_int(ATTR(update, "FROMROOM"), -2);
 
1498
 
 
1499
                _ggzcore_room_add_player(room, player, from_room);
 
1500
        } else if (strcasecmp(action, "delete") == 0) {
 
1501
                int to_room = str_to_int(ATTR(update, "TOROOM"), -2);
 
1502
 
 
1503
                _ggzcore_room_remove_player(room, player_name, to_room);
 
1504
        } else if (strcasecmp(action, "lag") == 0) {
1236
1505
                /* FIXME: Should be a player "class-based" event */
1237
 
                _ggzcore_room_set_player_lag(room, player->name, player->lag);
 
1506
                int lag = ggzcore_player_get_lag(player);
 
1507
 
 
1508
                _ggzcore_room_set_player_lag(room, player_name, lag);
1238
1509
        } else if (strcasecmp(action, "stats") == 0) {
1239
1510
                /* FIXME: Should be a player "class-based" event */
1240
1511
                _ggzcore_room_set_player_stats(room, player);
1245
1516
 
1246
1517
 
1247
1518
/* Handle table update */
1248
 
static void _ggzcore_net_table_update(GGZNet *net, GGZXMLElement *update,
1249
 
                                      char *action)
 
1519
static void _ggzcore_net_table_update(GGZNet * net, GGZXMLElement * update,
 
1520
                                      const char *action)
1250
1521
{
1251
 
        int i, room_num;
 
1522
        int i, room_num, table_id;
1252
1523
        GGZTable *table, *table_data;
1253
1524
        GGZRoom *room;
1254
 
        char *room_str;
 
1525
        const char *room_str;
1255
1526
 
1256
1527
        /* Sanity check: we can't proceed without a room number */
1257
1528
        room_str = ATTR(update, "ROOM");
1259
1530
                /* Assume we're talking about the current room.  This is
1260
1531
                   no doubt preferable to simply dropping the connection. */
1261
1532
                room = ggzcore_server_get_cur_room(net->server);
1262
 
                room_num = _ggzcore_room_get_id(room);
 
1533
                room_num = ggzcore_room_get_id(room);
1263
1534
        } else
1264
1535
                room_num = str_to_int(room_str, -1);
1265
1536
 
1275
1546
                _ggzcore_server_protocol_error(net->server, msg);
1276
1547
                return;
1277
1548
        }
1278
 
        
 
1549
 
1279
1550
        table_data = ggz_xmlelement_get_data(update);
1280
 
        table = _ggzcore_room_get_table_by_id(room, table_data->id);
 
1551
        table_id = ggzcore_table_get_id(table_data);
 
1552
        table = ggzcore_room_get_table_by_id(room, table_id);
1281
1553
 
1282
1554
        /* Table can only be NULL if we're adding it */
1283
1555
        if (!table && strcasecmp(action, "add") != 0) {
1284
1556
                char msg[256];
1285
1557
                snprintf(msg, sizeof(msg),
1286
1558
                         "Server specified non-existent table %d",
1287
 
                         table_data->id);
 
1559
                         table_id);
1288
1560
                _ggzcore_server_protocol_error(net->server, msg);
1289
1561
                return;
1290
1562
        }
1292
1564
        if (strcasecmp(action, "add") == 0) {
1293
1565
                _ggzcore_room_add_table(room, table_data);
1294
1566
                /* Set table_data to NULL so it doesn't get freed at
1295
 
                   the end of this function.  You would think this wouldn't
 
1567
                   the end of this function.  You would think this wouldn't
1296
1568
                   be necessary (since the table is inserted into a list,
1297
1569
                   which should copy it), but it appears as though it is. */
1298
1570
                table_data = NULL;
1299
1571
        } else if (strcasecmp(action, "delete") == 0)
1300
 
                _ggzcore_room_remove_table(room, table_data->id);
 
1572
                _ggzcore_room_remove_table(room, table_id);
1301
1573
        else if (strcasecmp(action, "join") == 0) {
1302
1574
                /* Loop over both seats and spectators. */
1303
 
                for (i = 0; i < table_data->num_seats; i++)
1304
 
                        if (table_data->seats[i].type != GGZ_SEAT_NONE)
1305
 
                                _ggzcore_table_set_seat(table,
1306
 
                                        &table_data->seats[i]);
1307
 
                for (i = 0; i < table_data->num_spectator_seats; i++) {
1308
 
                        if (table_data->spectator_seats[i].name) {
 
1575
                for (i = 0; i < ggzcore_table_get_num_seats(table_data);
 
1576
                     i++) {
 
1577
                        GGZTableSeat seat =
 
1578
                            _ggzcore_table_get_nth_seat(table_data, i);
 
1579
 
 
1580
                        if (seat.type != GGZ_SEAT_NONE) {
 
1581
                                _ggzcore_table_set_seat(table, &seat);
 
1582
                        }
 
1583
                }
 
1584
                for (i = 0;
 
1585
                     i < ggzcore_table_get_num_spectator_seats(table_data);
 
1586
                     i++) {
 
1587
                        GGZTableSeat spectator
 
1588
                            = _ggzcore_table_get_nth_spectator_seat
 
1589
                            (table_data, i);
 
1590
 
 
1591
                        if (spectator.name) {
1309
1592
                                _ggzcore_table_set_spectator_seat(table,
1310
 
                                        &table_data->spectator_seats[i]);
 
1593
                                                                  &spectator);
1311
1594
                        }
1312
1595
                }
1313
1596
        } else if (strcasecmp(action, "leave") == 0) {
1314
1597
                /* The server sends us the player that is leaving - that
1315
1598
                   is, a GGZ_SEAT_PLAYER not a GGZ_SEAT_OPEN.  It may
1316
1599
                   be either a regular or a spectator seat. */
1317
 
                for (i = 0; i < table_data->num_seats; i++) {
1318
 
                        if (table_data->seats[i].type != GGZ_SEAT_NONE) {
 
1600
                for (i = 0; i < ggzcore_table_get_num_seats(table_data);
 
1601
                     i++) {
 
1602
                        GGZTableSeat leave_seat =
 
1603
                            _ggzcore_table_get_nth_seat(table_data, i);
 
1604
 
 
1605
                        if (leave_seat.type != GGZ_SEAT_NONE) {
1319
1606
                                /* Player is vacating seat */
1320
 
                                struct _GGZSeat seat;
 
1607
                                GGZTableSeat seat;
1321
1608
                                seat.index = i;
1322
1609
                                seat.type = GGZ_SEAT_OPEN;
1323
1610
                                seat.name = NULL;
1324
1611
                                _ggzcore_table_set_seat(table, &seat);
1325
1612
                        }
1326
1613
                }
1327
 
                for (i = 0; i < table_data->num_spectator_seats; i++) {
1328
 
                        if (table_data->spectator_seats[i].name) {
 
1614
                for (i = 0;
 
1615
                     i < ggzcore_table_get_num_spectator_seats(table_data);
 
1616
                     i++) {
 
1617
                        GGZTableSeat leave_spectator
 
1618
                            = _ggzcore_table_get_nth_spectator_seat
 
1619
                            (table_data, i);
 
1620
 
 
1621
                        if (leave_spectator.name) {
1329
1622
                                /* Player is vacating seat */
1330
 
                                struct _GGZSeat seat;
 
1623
                                GGZTableSeat seat;
1331
1624
                                seat.index = i;
1332
1625
                                seat.name = NULL;
1333
1626
                                _ggzcore_table_set_spectator_seat(table,
1335
1628
                        }
1336
1629
                }
1337
1630
        } else if (strcasecmp(action, "status") == 0) {
1338
 
                _ggzcore_table_set_state(table, table_data->state);
 
1631
                _ggzcore_table_set_state(table,
 
1632
                                         ggzcore_table_get_state
 
1633
                                         (table_data));
1339
1634
        } else if (strcasecmp(action, "desc") == 0) {
1340
 
                _ggzcore_table_set_desc(table, table_data->desc);
 
1635
                _ggzcore_table_set_desc(table,
 
1636
                                        ggzcore_table_get_desc
 
1637
                                        (table_data));
1341
1638
        } else if (strcasecmp(action, "seat") == 0) {
1342
 
                for (i = 0; i < table_data->num_seats; i++) 
1343
 
                        if (table_data->seats[i].type != GGZ_SEAT_NONE)
1344
 
                                _ggzcore_table_set_seat(table, &table_data->seats[i]);
 
1639
                for (i = 0; i < ggzcore_table_get_num_seats(table_data);
 
1640
                     i++) {
 
1641
                        GGZTableSeat seat =
 
1642
                            _ggzcore_table_get_nth_seat(table_data, i);
 
1643
 
 
1644
                        if (seat.type != GGZ_SEAT_NONE) {
 
1645
                                _ggzcore_table_set_seat(table, &seat);
 
1646
                        }
 
1647
                }
1345
1648
        }
1346
 
                        
 
1649
 
1347
1650
        if (table_data)
1348
1651
                _ggzcore_table_free(table_data);
1349
1652
 
1351
1654
 
1352
1655
 
1353
1656
/* Functions for <GAME> tag */
1354
 
static void _ggzcore_net_handle_game(GGZNet *net, GGZXMLElement *element)
 
1657
static void _ggzcore_net_handle_game(GGZNet * net, GGZXMLElement * element)
1355
1658
{
1356
1659
        GGZGameType *type;
1357
1660
        GGZGameData *data;
1358
1661
        GGZXMLElement *parent;
1359
1662
        const char *parent_tag, *parent_type;
1360
1663
        int id;
1361
 
        char *name, *version;
 
1664
        const char *name, *version;
1362
1665
        const char *prot_engine = NULL;
1363
1666
        const char *prot_version = NULL;
1364
1667
        GGZNumberList player_allow_list = ggz_numberlist_new();
1365
1668
        GGZNumberList bot_allow_list = ggz_numberlist_new();
1366
1669
        int spectators_allow = 0;
 
1670
        int peers_allow = 0;
1367
1671
        const char *desc = NULL;
1368
1672
        const char *author = NULL;
1369
1673
        const char *url = NULL;
 
1674
        int i;
1370
1675
 
1371
1676
        if (!element)
1372
1677
                return;
1383
1688
                player_allow_list = data->player_allow_list;
1384
1689
                bot_allow_list = data->bot_allow_list;
1385
1690
                spectators_allow = data->spectators_allow;
 
1691
                peers_allow = data->peers_allow;
1386
1692
                desc = data->desc;
1387
1693
                author = data->author;
1388
1694
                url = data->url;
1390
1696
 
1391
1697
        type = _ggzcore_gametype_new();
1392
1698
        _ggzcore_gametype_init(type, id, name, version, prot_engine,
1393
 
                               prot_version, 
 
1699
                               prot_version,
1394
1700
                               player_allow_list, bot_allow_list,
1395
 
                               spectators_allow, desc, author, url);
 
1701
                               spectators_allow, peers_allow,
 
1702
                               desc, author, url);
 
1703
 
 
1704
        if (data->named_bots) {
 
1705
                for (i = 0; data->named_bots[i]; i++) {
 
1706
                        _ggzcore_gametype_add_namedbot(type,
 
1707
                                data->named_bots[i][0],
 
1708
                                data->named_bots[i][1]);
 
1709
                }
 
1710
        }
1396
1711
 
1397
1712
        /* Get parent off top of stack */
1398
1713
        parent = ggz_stack_top(net->stack);
1419
1734
                if (data->desc)
1420
1735
                        ggz_free(data->desc);
1421
1736
 
 
1737
                if (data->named_bots) {
 
1738
                        for (i = 0; data->named_bots[i]; i++) {
 
1739
                                ggz_free(data->named_bots[i][0]);
 
1740
                                ggz_free(data->named_bots[i][1]);
 
1741
                                ggz_free(data->named_bots[i]);
 
1742
                        }
 
1743
                        ggz_free(data->named_bots);
 
1744
                }
 
1745
 
1422
1746
                ggz_free(data);
1423
1747
        }
1424
1748
}
1426
1750
 
1427
1751
/* This should not be called by the parent tag, but only by the
1428
1752
   child tags to set data for the parent. */
1429
 
static GGZGameData *_ggzcore_net_game_get_data(GGZXMLElement *game)
 
1753
static GGZGameData *_ggzcore_net_game_get_data(GGZXMLElement * game)
1430
1754
{
1431
1755
        GGZGameData *data = ggz_xmlelement_get_data(game);
1432
1756
 
1440
1764
}
1441
1765
 
1442
1766
 
1443
 
static void _ggzcore_net_game_set_protocol(GGZXMLElement *game,
1444
 
                                           char *engine, char *version)
 
1767
static GGZPlayerInfoData *_ggzcore_net_playerinfo_get_data(GGZXMLElement * info)
 
1768
{
 
1769
        GGZPlayerInfoData *data = ggz_xmlelement_get_data(info);
 
1770
 
 
1771
        /* If data doesn't already exist, create it */
 
1772
        if (!data) {
 
1773
                data = ggz_malloc(sizeof(GGZPlayerInfoData));
 
1774
                ggz_xmlelement_set_data(info, data);
 
1775
 
 
1776
                data->infos = ggz_list_create(NULL,
 
1777
                        /*(ggzEntryCreate)_ggzcore_net_seat_copy*/
 
1778
                        NULL,
 
1779
                        /*(ggzEntryDestroy)_ggzcore_net_seat_free*/
 
1780
                        NULL,
 
1781
                        GGZ_LIST_ALLOW_DUPS);
 
1782
        }
 
1783
 
 
1784
        return data;
 
1785
}
 
1786
 
 
1787
 
 
1788
static void _ggzcore_net_game_set_protocol(GGZXMLElement * game,
 
1789
                                           const char *engine,
 
1790
                                           const char *version)
1445
1791
{
1446
1792
        GGZGameData *data = _ggzcore_net_game_get_data(game);
1447
1793
 
1452
1798
}
1453
1799
 
1454
1800
 
1455
 
static void _ggzcore_net_game_set_allowed(GGZXMLElement *game,
1456
 
                                          GGZNumberList players, 
 
1801
static void _ggzcore_net_game_set_allowed(GGZXMLElement * game,
 
1802
                                          GGZNumberList players,
1457
1803
                                          GGZNumberList bots,
1458
 
                                          int spectators)
 
1804
                                          int spectators,
 
1805
                                          int peers)
1459
1806
{
1460
1807
        GGZGameData *data = _ggzcore_net_game_get_data(game);
1461
1808
 
1462
1809
        data->player_allow_list = players;
1463
1810
        data->bot_allow_list = bots;
1464
1811
        data->spectators_allow = spectators;
 
1812
        data->peers_allow = peers;
1465
1813
}
1466
1814
 
1467
1815
 
1468
 
static void _ggzcore_net_game_set_info(GGZXMLElement *game,
1469
 
                                       char *author, char *url)
 
1816
static void _ggzcore_net_game_set_info(GGZXMLElement * game,
 
1817
                                       const char *author, const char *url)
1470
1818
{
1471
1819
        GGZGameData *data = _ggzcore_net_game_get_data(game);
1472
1820
 
1477
1825
}
1478
1826
 
1479
1827
 
1480
 
static void _ggzcore_net_game_set_desc(GGZXMLElement *game, char *desc)
 
1828
static void _ggzcore_net_game_add_bot(GGZXMLElement * game,
 
1829
                                       const char *botname, const char *botclass)
 
1830
{
 
1831
        GGZGameData *data = _ggzcore_net_game_get_data(game);
 
1832
        int size = 0;
 
1833
 
 
1834
        if (data->named_bots) {
 
1835
                while (data->named_bots[size]) size++;
 
1836
        }
 
1837
        data->named_bots = (char***)ggz_realloc(data->named_bots, (size + 2) * sizeof(char**));
 
1838
        data->named_bots[size] = (char**)ggz_malloc(2 * sizeof(char**));
 
1839
        data->named_bots[size][0] = ggz_strdup(botname);
 
1840
        data->named_bots[size][1] = ggz_strdup(botclass);
 
1841
        data->named_bots[size + 1] = NULL;
 
1842
}
 
1843
 
 
1844
 
 
1845
static void _ggzcore_net_playerinfo_add_seat(GGZXMLElement * info, int num,
 
1846
        const char *realname, const char *photo, const char *host)
 
1847
{
 
1848
        GGZPlayerInfoData *data = _ggzcore_net_playerinfo_get_data(info);
 
1849
        GGZPlayerInfo *tmp = (GGZPlayerInfo*)ggz_malloc(sizeof(GGZPlayerInfo));
 
1850
 
 
1851
        tmp->num = num;
 
1852
        tmp->realname = ggz_strdup(realname);
 
1853
        tmp->photo = ggz_strdup(photo);
 
1854
        tmp->host = ggz_strdup(host);
 
1855
 
 
1856
        ggz_list_insert(data->infos, tmp);
 
1857
}
 
1858
 
 
1859
 
 
1860
static void _ggzcore_net_game_set_desc(GGZXMLElement * game, char *desc)
1481
1861
{
1482
1862
        GGZGameData *data = _ggzcore_net_game_get_data(game);
1483
1863
 
1487
1867
 
1488
1868
 
1489
1869
/* Functions for <PROTOCOL> tag */
1490
 
static void _ggzcore_net_handle_protocol(GGZNet *net, GGZXMLElement *element)
 
1870
static void _ggzcore_net_handle_protocol(GGZNet * net,
 
1871
                                         GGZXMLElement * element)
1491
1872
{
1492
1873
        GGZXMLElement *parent;
1493
1874
        const char *parent_tag;
1511
1892
 
1512
1893
 
1513
1894
/* Functions for <ALLOW> tag */
1514
 
static void _ggzcore_net_handle_allow(GGZNet *net, GGZXMLElement *element)
 
1895
static void _ggzcore_net_handle_allow(GGZNet * net,
 
1896
                                      GGZXMLElement * element)
1515
1897
{
1516
1898
        GGZXMLElement *parent;
1517
1899
        const char *parent_tag;
1518
1900
        GGZNumberList players, bots;
1519
 
        int spectators;
 
1901
        int spectators, peers;
1520
1902
 
1521
1903
        if (!element)
1522
1904
                return;
1533
1915
        players = ggz_numberlist_read(ATTR(element, "PLAYERS"));
1534
1916
        bots = ggz_numberlist_read(ATTR(element, "BOTS"));
1535
1917
        spectators = str_to_bool(ATTR(element, "SPECTATORS"), 0);
 
1918
        peers = str_to_bool(ATTR(element, "PEERS"), 0);
1536
1919
 
1537
 
        _ggzcore_net_game_set_allowed(parent, players, bots, spectators);
 
1920
        _ggzcore_net_game_set_allowed(parent, players, bots, spectators, peers);
1538
1921
}
1539
1922
 
1540
1923
 
1541
1924
/* Functions for <ABOUT> tag */
1542
 
static void _ggzcore_net_handle_about(GGZNet *net, GGZXMLElement *element)
 
1925
static void _ggzcore_net_handle_about(GGZNet * net,
 
1926
                                      GGZXMLElement * element)
1543
1927
{
1544
1928
        GGZXMLElement *parent;
1545
1929
        const char *parent_tag;
1556
1940
        if (strcasecmp(parent_tag, "GAME") != 0)
1557
1941
                return;
1558
1942
 
1559
 
        _ggzcore_net_game_set_info(parent, 
 
1943
        _ggzcore_net_game_set_info(parent,
1560
1944
                                   ATTR(element, "AUTHOR"),
1561
1945
                                   ATTR(element, "URL"));
1562
1946
}
1563
1947
 
1564
1948
 
 
1949
/* Functions for <BOT> tag */
 
1950
static void _ggzcore_net_handle_bot(GGZNet * net,
 
1951
                                    GGZXMLElement * element)
 
1952
{
 
1953
        GGZXMLElement *parent;
 
1954
        const char *parent_tag;
 
1955
 
 
1956
        if (!element)
 
1957
                return;
 
1958
 
 
1959
        /* Get parent off top of stack */
 
1960
        parent = ggz_stack_top(net->stack);
 
1961
        if (!parent)
 
1962
                return;
 
1963
 
 
1964
        parent_tag = ggz_xmlelement_get_tag(parent);
 
1965
        if (strcasecmp(parent_tag, "GAME") != 0)
 
1966
                return;
 
1967
 
 
1968
        _ggzcore_net_game_add_bot(parent,
 
1969
                                  ATTR(element, "NAME"),
 
1970
                                  ATTR(element, "CLASS"));
 
1971
}
 
1972
 
 
1973
 
1565
1974
/* Functions for <DESC> tag */
1566
 
static void _ggzcore_net_handle_desc(GGZNet *net, GGZXMLElement *element)
 
1975
static void _ggzcore_net_handle_desc(GGZNet * net, GGZXMLElement * element)
1567
1976
{
1568
1977
        char *desc;
1569
1978
        const char *parent_tag;
1593
2002
 
1594
2003
 
1595
2004
/* Functions for <ROOM> tag */
1596
 
static void _ggzcore_net_handle_room(GGZNet *net, GGZXMLElement *element)
 
2005
static void _ggzcore_net_handle_room(GGZNet * net, GGZXMLElement * element)
1597
2006
{
1598
2007
        GGZRoom *ggz_room;
1599
 
        int id, game;
1600
 
        char *name, *desc;
1601
 
        GGZXMLElement *parent;
 
2008
        int id, game, players;
 
2009
        const char *name, *desc;
 
2010
        GGZXMLElement *parent = ggz_stack_top(net->stack);
1602
2011
        const char *parent_tag, *parent_type;
1603
2012
 
1604
2013
        if (!element)
1605
2014
                return;
1606
2015
 
 
2016
        if (!parent) {
 
2017
                return;
 
2018
        }
 
2019
 
1607
2020
        /* Grab data from tag */
1608
2021
        id = str_to_int(ATTR(element, "ID"), -1);
1609
2022
        name = ATTR(element, "NAME");
1610
2023
        game = str_to_int(ATTR(element, "GAME"), -1);
1611
2024
        desc = ggz_xmlelement_get_data(element);
 
2025
        players = str_to_int(ATTR(element, "PLAYERS"), -1);
1612
2026
 
1613
2027
        /* Set up GGZRoom object */
1614
2028
        ggz_room = _ggzcore_room_new();
1615
 
        _ggzcore_room_init(ggz_room, net->server, id, name, game, desc);
 
2029
        _ggzcore_room_init(ggz_room, net->server, id,
 
2030
                           name, game, desc, players);
1616
2031
 
1617
2032
        /* Free description if present */
1618
2033
        if (desc)
1619
2034
                ggz_free(desc);
1620
2035
 
1621
2036
        /* Get parent off top of stack */
1622
 
        parent = ggz_stack_top(net->stack);
1623
2037
        parent_tag = ggz_xmlelement_get_tag(parent);
1624
2038
        parent_type = ATTR(parent, "TYPE");
1625
2039
 
1626
 
        if (parent
1627
 
            && strcasecmp(parent_tag, "LIST") == 0
1628
 
            && strcasecmp(parent_type, "room") == 0)
 
2040
        if (strcasecmp(parent_tag, "LIST") == 0
 
2041
            && strcasecmp(parent_type, "room") == 0) {
1629
2042
                _ggzcore_net_list_insert(parent, ggz_room);
1630
 
        else
 
2043
        } else if (strcasecmp(parent_tag, "UPDATE") == 0
 
2044
                   && strcasecmp(parent_type, "room") == 0
 
2045
                   && ggz_xmlelement_get_data(parent) == NULL) {
 
2046
                ggz_xmlelement_set_data(parent, ggz_room);
 
2047
        } else {
1631
2048
                _ggzcore_room_free(ggz_room);
 
2049
        }
1632
2050
}
1633
2051
 
1634
2052
 
1635
2053
/* Functions for <PLAYER> tag */
1636
 
static void _ggzcore_net_handle_player(GGZNet *net, GGZXMLElement *element)
 
2054
static void _ggzcore_net_handle_player(GGZNet * net,
 
2055
                                       GGZXMLElement * element)
1637
2056
{
1638
2057
        GGZPlayer *ggz_player;
1639
2058
        GGZPlayerType type;
1640
2059
        GGZRoom *room;
1641
 
        char *name, *str_type;
 
2060
        const char *name, *str_type;
1642
2061
        int table, lag;
1643
2062
        GGZXMLElement *parent;
1644
2063
        const char *parent_tag, *parent_type;
 
2064
        int wins, losses, ties, forfeits, rating, ranking, highscore;
1645
2065
 
1646
2066
        if (!element)
1647
2067
                return;
1655
2075
        lag = str_to_int(ATTR(element, "LAG"), 0);
1656
2076
 
1657
2077
        /* Set player's type */
1658
 
        if (!str_type || strcasecmp(str_type, "guest") == 0)
1659
 
                type = GGZ_PLAYER_GUEST;
1660
 
        else if (strcasecmp(str_type, "normal") == 0)
1661
 
                type = GGZ_PLAYER_NORMAL;
1662
 
        else if (strcasecmp(str_type, "admin") == 0)
1663
 
                type = GGZ_PLAYER_ADMIN;
1664
 
        else
1665
 
                type = GGZ_PLAYER_GUEST;
 
2078
        type = ggz_string_to_playertype(str_type);
1666
2079
 
1667
2080
        /* Set up GGZPlayer object */
1668
2081
        ggz_player = _ggzcore_player_new();
1669
 
        _ggzcore_player_init(ggz_player,  name, room, table, type, lag);
 
2082
        _ggzcore_player_init(ggz_player, name, room, table, type, lag);
1670
2083
 
1671
2084
        /* FIXME: should these be initialized through an accessor function? */
1672
 
        ggz_player->wins = str_to_int(ATTR(element, "WINS"), NO_RECORD);
1673
 
        ggz_player->ties = str_to_int(ATTR(element, "TIES"), NO_RECORD);
1674
 
        ggz_player->losses = str_to_int(ATTR(element, "LOSSES"), NO_RECORD);
1675
 
        ggz_player->forfeits = str_to_int(ATTR(element, "FORFEITS"),
1676
 
                                          NO_RECORD);
1677
 
        ggz_player->rating = str_to_int(ATTR(element, "RATING"), NO_RATING);
1678
 
        ggz_player->ranking = str_to_int(ATTR(element, "RANKING"), NO_RANKING);
1679
 
 
1680
 
        /* FIXME: highscore is a long... */
1681
 
        ggz_player->highscore = str_to_int(ATTR(element, "HIGHSCORE"),
1682
 
                                           NO_HIGHSCORE);
 
2085
        wins = str_to_int(ATTR(element, "WINS"), NO_RECORD);
 
2086
        ties = str_to_int(ATTR(element, "TIES"), NO_RECORD);
 
2087
        losses = str_to_int(ATTR(element, "LOSSES"), NO_RECORD);
 
2088
        forfeits = str_to_int(ATTR(element, "FORFEITS"), NO_RECORD);
 
2089
        rating = str_to_int(ATTR(element, "RATING"), NO_RATING);
 
2090
        ranking = str_to_int(ATTR(element, "RANKING"), NO_RANKING);
 
2091
        highscore = str_to_int(ATTR(element, "HIGHSCORE"), NO_HIGHSCORE);
 
2092
        _ggzcore_player_init_stats(ggz_player, wins, losses, ties,
 
2093
                                   forfeits, rating, ranking, highscore);
1683
2094
 
1684
2095
        /* Get parent off top of stack */
1685
2096
        parent = ggz_stack_top(net->stack);
1700
2111
 
1701
2112
 
1702
2113
/* Functions for <TABLE> tag */
1703
 
static void _ggzcore_net_handle_table(GGZNet *net, GGZXMLElement *element)
 
2114
static void _ggzcore_net_handle_table(GGZNet * net,
 
2115
                                      GGZXMLElement * element)
1704
2116
{
1705
2117
        GGZGameType *type;
1706
2118
        GGZTableData *data;
1736
2148
 
1737
2149
        /* Initialize seats to none */
1738
2150
        /* FIXME: perhaps tables should come this way? */
1739
 
        for (i = 0; i < num_seats; i++)
1740
 
                table_obj->seats[i].type = GGZ_SEAT_NONE;
 
2151
        for (i = 0; i < num_seats; i++) {
 
2152
                GGZTableSeat seat =
 
2153
                    _ggzcore_table_get_nth_seat(table_obj, i);
 
2154
 
 
2155
                seat.type = GGZ_SEAT_NONE;
 
2156
                _ggzcore_table_set_seat(table_obj, &seat);
 
2157
        }
1741
2158
 
1742
2159
        /* Add seats */
1743
2160
        entry = ggz_list_head(seats);
1744
2161
        while (entry) {
1745
 
                struct _GGZSeat* seat = ggz_list_get_data(entry);
 
2162
                GGZTableSeat *seat = ggz_list_get_data(entry);
1746
2163
                _ggzcore_table_set_seat(table_obj, seat);
1747
2164
                entry = ggz_list_next(entry);
1748
2165
        }
1750
2167
        /* Add spectator seats */
1751
2168
        entry = ggz_list_head(spectatorseats);
1752
2169
        while (entry) {
1753
 
                struct _GGZSeat* seat = ggz_list_get_data(entry);
 
2170
                GGZTableSeat *seat = ggz_list_get_data(entry);
1754
2171
                _ggzcore_table_set_spectator_seat(table_obj, seat);
1755
2172
                entry = ggz_list_next(entry);
1756
2173
        }
1777
2194
                _ggzcore_net_tabledata_free(data);
1778
2195
}
1779
2196
 
1780
 
static GGZTableData *_ggzcore_net_table_get_data(GGZXMLElement *table)
 
2197
static GGZTableData *_ggzcore_net_table_get_data(GGZXMLElement * table)
1781
2198
{
1782
2199
        GGZTableData *data = ggz_xmlelement_get_data(table);
1783
2200
 
1790
2207
        return data;
1791
2208
}
1792
2209
 
1793
 
static void _ggzcore_net_table_add_seat(GGZXMLElement *table,
1794
 
                                        struct _GGZSeat *seat,
1795
 
                                        int spectator)
 
2210
static void _ggzcore_net_table_add_seat(GGZXMLElement * table,
 
2211
                                        GGZTableSeat * seat, int spectator)
1796
2212
{
1797
2213
        GGZTableData *data = _ggzcore_net_table_get_data(table);
1798
2214
 
1803
2219
        }
1804
2220
}
1805
2221
 
1806
 
static void _ggzcore_net_table_set_desc(GGZXMLElement *table, char *desc)
 
2222
static void _ggzcore_net_table_set_desc(GGZXMLElement * table, char *desc)
1807
2223
{
1808
2224
        GGZTableData *data = _ggzcore_net_table_get_data(table);
1809
2225
 
1812
2228
}
1813
2229
 
1814
2230
 
1815
 
static GGZTableData* _ggzcore_net_tabledata_new(void)
 
2231
static GGZTableData *_ggzcore_net_tabledata_new(void)
1816
2232
{
1817
2233
        GGZTableData *data = ggz_malloc(sizeof(GGZTableData));
1818
2234
 
1819
 
        data->seats = ggz_list_create(NULL, 
1820
 
                                      (ggzEntryCreate)_ggzcore_net_seat_copy, 
1821
 
                                      (ggzEntryDestroy)_ggzcore_net_seat_free, 
 
2235
        data->seats = ggz_list_create(NULL, (ggzEntryCreate)
 
2236
                                      _ggzcore_net_seat_copy,
 
2237
                                      (ggzEntryDestroy)
 
2238
                                      _ggzcore_net_seat_free,
1822
2239
                                      GGZ_LIST_ALLOW_DUPS);
1823
2240
 
1824
 
        data->spectatorseats = ggz_list_create(NULL, 
1825
 
                                (ggzEntryCreate)_ggzcore_net_seat_copy, 
1826
 
                                (ggzEntryDestroy)_ggzcore_net_seat_free, 
1827
 
                                GGZ_LIST_ALLOW_DUPS);
 
2241
        data->spectatorseats = ggz_list_create(NULL, (ggzEntryCreate)
 
2242
                                               _ggzcore_net_seat_copy,
 
2243
                                               (ggzEntryDestroy)
 
2244
                                               _ggzcore_net_seat_free,
 
2245
                                               GGZ_LIST_ALLOW_DUPS);
1828
2246
 
1829
2247
        return data;
1830
2248
}
1831
2249
 
1832
2250
 
1833
 
static void _ggzcore_net_tabledata_free(GGZTableData *data)
 
2251
static void _ggzcore_net_tabledata_free(GGZTableData * data)
1834
2252
{
1835
2253
        if (!data)
1836
2254
                return;
1846
2264
 
1847
2265
 
1848
2266
/* Functions for <SEAT> tag */
1849
 
static void _ggzcore_net_handle_seat(GGZNet *net, GGZXMLElement *element)
 
2267
static void _ggzcore_net_handle_seat(GGZNet * net, GGZXMLElement * element)
1850
2268
{
1851
 
        struct _GGZSeat seat_obj;
 
2269
        GGZTableSeat seat_obj;
1852
2270
        GGZXMLElement *parent;
1853
2271
        const char *parent_tag;
1854
2272
 
1862
2280
 
1863
2281
        /* Make sure parent is <TABLE> */
1864
2282
        parent_tag = ggz_xmlelement_get_tag(parent);
1865
 
        if (!parent_tag
1866
 
            || strcasecmp(parent_tag, "TABLE"))
 
2283
        if (!parent_tag || strcasecmp(parent_tag, "TABLE"))
1867
2284
                return;
1868
2285
 
1869
2286
        /* Get seat information out of tag */
1874
2291
}
1875
2292
 
1876
2293
/* Functions for <SPECTATOR> tag */
1877
 
static void _ggzcore_net_handle_spectator_seat(GGZNet *net,
1878
 
                                               GGZXMLElement *element)
 
2294
static void _ggzcore_net_handle_spectator_seat(GGZNet * net,
 
2295
                                               GGZXMLElement * element)
1879
2296
{
1880
 
        struct _GGZSeat seat_obj;
 
2297
        GGZTableSeat seat_obj;
1881
2298
        GGZXMLElement *parent;
1882
2299
        const char *parent_tag;
1883
2300
 
1891
2308
 
1892
2309
        /* Make sure parent is <TABLE> */
1893
2310
        parent_tag = ggz_xmlelement_get_tag(parent);
1894
 
        if (!parent_tag
1895
 
            || strcasecmp(parent_tag, "TABLE"))
 
2311
        if (!parent_tag || strcasecmp(parent_tag, "TABLE"))
1896
2312
                return;
1897
2313
 
1898
2314
        /* Get seat information out of tag */
1901
2317
        _ggzcore_net_table_add_seat(parent, &seat_obj, 1);
1902
2318
}
1903
2319
 
1904
 
static struct _GGZSeat* _ggzcore_net_seat_copy(struct _GGZSeat *orig)
 
2320
static GGZTableSeat *_ggzcore_net_seat_copy(GGZTableSeat * orig)
1905
2321
{
1906
 
        struct _GGZSeat *copy;
 
2322
        GGZTableSeat *copy;
1907
2323
 
1908
 
        copy = ggz_malloc(sizeof(struct _GGZSeat));
 
2324
        copy = ggz_malloc(sizeof(GGZTableSeat));
1909
2325
 
1910
2326
        copy->index = orig->index;
1911
2327
        copy->type = orig->type;
1915
2331
}
1916
2332
 
1917
2333
 
1918
 
static void _ggzcore_net_seat_free(struct _GGZSeat *seat)
 
2334
static void _ggzcore_net_seat_free(GGZTableSeat * seat)
1919
2335
{
1920
2336
        if (!seat)
1921
2337
                return;
1926
2342
}
1927
2343
 
1928
2344
 
1929
 
static void _ggzcore_net_handle_leave(GGZNet *net, GGZXMLElement *element)
 
2345
static void _ggzcore_net_handle_leave(GGZNet * net,
 
2346
                                      GGZXMLElement * element)
1930
2347
{
1931
2348
        GGZRoom *room;
1932
2349
        GGZLeaveType reason;
1933
2350
        const char *player;
1934
2351
 
1935
 
        if (!element) return;
 
2352
        if (!element)
 
2353
                return;
1936
2354
 
1937
2355
        room = _ggzcore_server_get_cur_room(net->server);
1938
2356
        reason = ggz_string_to_leavetype(ATTR(element, "REASON"));
1942
2360
}
1943
2361
 
1944
2362
 
1945
 
static void _ggzcore_net_handle_join(GGZNet *net, GGZXMLElement *element)
 
2363
static void _ggzcore_net_handle_join(GGZNet * net, GGZXMLElement * element)
1946
2364
{
1947
2365
        GGZRoom *room;
1948
2366
        int table;
1949
2367
 
1950
 
        if (!element) return;
 
2368
        if (!element)
 
2369
                return;
1951
2370
 
1952
2371
        room = _ggzcore_server_get_cur_room(net->server);
1953
2372
        table = str_to_int(ATTR(element, "TABLE"), -1);
1957
2376
 
1958
2377
 
1959
2378
/* Functions for <CHAT> tag */
1960
 
static void _ggzcore_net_handle_chat(GGZNet *net, GGZXMLElement *element)
 
2379
static void _ggzcore_net_handle_chat(GGZNet * net, GGZXMLElement * element)
1961
2380
{
1962
 
        char *msg, *type_str, *from;
 
2381
        const char *msg, *type_str, *from;
 
2382
        char *msg_unquoted;
1963
2383
        GGZRoom *room;
1964
2384
        GGZChatType type;
1965
2385
 
1966
 
        if (!element) return;
 
2386
        if (!element)
 
2387
                return;
1967
2388
 
1968
2389
        /* Grab chat data from tag */
1969
2390
        type_str = ATTR(element, "TYPE");
1971
2392
        msg = ggz_xmlelement_get_text(element);
1972
2393
 
1973
2394
        ggz_debug(GGZCORE_DBG_NET, "%s message from %s: '%s'",
1974
 
                  type_str, from, msg); 
 
2395
                  type_str, from, msg);
1975
2396
 
1976
2397
        type = ggz_string_to_chattype(type_str);
1977
2398
 
1980
2401
                return;
1981
2402
        }
1982
2403
 
1983
 
        if (!msg
1984
 
            && type != GGZ_CHAT_BEEP
1985
 
            && type != GGZ_CHAT_UNKNOWN) {
 
2404
        if (!msg && type != GGZ_CHAT_BEEP && type != GGZ_CHAT_UNKNOWN) {
1986
2405
                /* Ignore an empty message, except for the
1987
2406
                   appropriate chat types. */
1988
2407
                return;
1989
2408
        }
1990
2409
 
 
2410
        msg_unquoted = _ggz_xml_cdata_unescape(msg);
 
2411
 
1991
2412
        room = ggzcore_server_get_cur_room(net->server);
1992
 
        _ggzcore_room_add_chat(room, type, from, msg);
 
2413
        _ggzcore_room_add_chat(room, type, from, msg_unquoted);
 
2414
 
 
2415
        if (msg_unquoted)
 
2416
                ggz_free(msg_unquoted);
 
2417
}
 
2418
 
 
2419
 
 
2420
/* Functions for <INFO> tag */
 
2421
static void _ggzcore_net_handle_info(GGZNet * net, GGZXMLElement * element)
 
2422
{
 
2423
        GGZPlayerInfoData *data = _ggzcore_net_playerinfo_get_data(element);
 
2424
 
 
2425
        GGZGame *game = ggzcore_server_get_cur_game(net->server);
 
2426
        _ggzcore_game_set_info(game, ggz_list_count(data->infos), data->infos);
 
2427
}
 
2428
 
 
2429
 
 
2430
/* Functions for <PLAYERINFO> tag */
 
2431
static void _ggzcore_net_handle_playerinfo(GGZNet * net, GGZXMLElement * element)
 
2432
{
 
2433
        GGZXMLElement *parent;
 
2434
        const char *parent_tag;
 
2435
 
 
2436
        if (!element)
 
2437
                return;
 
2438
 
 
2439
        /* Get parent off top of stack */
 
2440
        parent = ggz_stack_top(net->stack);
 
2441
        if (!parent)
 
2442
                return;
 
2443
 
 
2444
        parent_tag = ggz_xmlelement_get_tag(parent);
 
2445
        if (strcasecmp(parent_tag, "INFO") != 0)
 
2446
                return;
 
2447
 
 
2448
        _ggzcore_net_playerinfo_add_seat(parent,
 
2449
                                  str_to_int(ATTR(element, "SEAT"), -1),
 
2450
                                  ATTR(element, "REALNAME"),
 
2451
                                  ATTR(element, "PHOTO"),
 
2452
                                  ATTR(element, "HOST"));
1993
2453
}
1994
2454
 
1995
2455
 
1996
2456
/* Function for <PING> tag */
1997
 
static void _ggzcore_net_handle_ping(GGZNet *net, GGZXMLElement *element)
 
2457
static void _ggzcore_net_handle_ping(GGZNet * net, GGZXMLElement * element)
1998
2458
{
1999
2459
        /* No need to bother the client or anything, just send pong */
2000
2460
        const char *id = ATTR(element, "ID");
2003
2463
 
2004
2464
 
2005
2465
/* Function for <SESSION> tag */
2006
 
static void _ggzcore_net_handle_session(GGZNet *net, GGZXMLElement *element)
 
2466
static void _ggzcore_net_handle_session(GGZNet * net,
 
2467
                                        GGZXMLElement * element)
2007
2468
{
2008
2469
        /* Note we only get this after </SESSION> is sent. */
2009
2470
        _ggzcore_server_session_over(net->server, net);
2010
2471
}
2011
2472
 
2012
2473
/* Send the session header */
2013
 
void _ggzcore_net_send_header(GGZNet *net)
 
2474
void _ggzcore_net_send_header(GGZNet * net)
2014
2475
{
2015
2476
        _ggzcore_net_send_line(net,
2016
 
                               "<?xml version='1.0' encoding='ISO-8859-1'?>");
 
2477
                               "<?xml version='1.0' encoding='UTF-8'?>");
2017
2478
        _ggzcore_net_send_line(net, "<SESSION>");
2018
2479
}
2019
2480
 
2020
2481
 
2021
 
int _ggzcore_net_send_pong(GGZNet *net, const char *id)
 
2482
int _ggzcore_net_send_pong(GGZNet * net, const char *id)
2022
2483
{
2023
2484
        if (id)
2024
2485
                return _ggzcore_net_send_line(net, "<PONG ID='%s'/>", id);
2028
2489
 
2029
2490
 
2030
2491
/* Send a TLS_START notice and negotiate the handshake */
2031
 
static void _ggzcore_net_negotiate_tls(GGZNet *net)
 
2492
static void _ggzcore_net_negotiate_tls(GGZNet * net)
2032
2493
{
2033
2494
        int ret;
2034
2495
 
2035
2496
        _ggzcore_net_send_line(net, "<TLS_START/>");
2036
2497
        /* This should return a status one day to tell client if */
2037
2498
        /* the handshake failed for some reason */
2038
 
        ret = ggz_tls_enable_fd(net->fd, GGZ_TLS_CLIENT, GGZ_TLS_VERIFY_NONE);
2039
 
        if(!ret) net->use_tls = 0;
 
2499
        ret =
 
2500
            ggz_tls_enable_fd(net->fd, GGZ_TLS_CLIENT,
 
2501
                              GGZ_TLS_VERIFY_NONE);
 
2502
        if (!ret)
 
2503
                net->use_tls = 0;
2040
2504
}
2041
2505
 
2042
2506
 
2043
 
static int _ggzcore_net_send_line(GGZNet *net, char *line, ...)
 
2507
static int _ggzcore_net_send_line(GGZNet * net, char *line, ...)
2044
2508
{
2045
2509
        char buf[4096];
2046
2510
        va_list ap;