/[LeafOK_CVS]/pvpgn-1.7.4/src/d2cs/handle_d2cs.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/d2cs/handle_d2cs.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations)
Tue Jun 13 05:06:23 2006 UTC (19 years, 9 months ago) by sysadm
Branch: MAIN
Changes since 1.2: +5 -10 lines
Content type: text/x-csrc
Improve Antibot

1 /*
2 * Copyright (C) 2000,2001 Onlyer (onlyer@263.net)
3 * Copyright (C) 2004 Olaf Freyer (aaron@cs.tu-berlin.de)
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 #include "common/setup_before.h"
20 #include "setup.h"
21
22 #include <stdio.h>
23 #ifdef HAVE_STRING_H
24 # include <string.h>
25 #else
26 # ifdef HAVE_STRINGS_H
27 # include <strings.h>
28 # endif
29 # ifdef HAVE_MEMORY_H
30 # include <memory.h>
31 # endif
32 #endif
33 #ifdef STDC_HEADERS
34 # include <stdlib.h>
35 #else
36 # ifdef HAVE_MALLOC_H
37 # include <malloc.h>
38 # endif
39 #endif
40 #include "compat/memcpy.h"
41 #ifdef TIME_WITH_SYS_TIME
42 # include <time.h>
43 # include <sys/time.h>
44 #else
45 # ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
47 # else
48 # include <time.h>
49 # endif
50 #endif
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #ifdef HAVE_SYS_STAT_H
55 # include <sys/stat.h>
56 #endif
57
58 #ifdef HAVE_SYS_SOCKET_H
59 # include <sys/socket.h>
60 #endif
61 #ifdef HAVE_NETINET_IN_H
62 # include <netinet/in.h>
63 #endif
64 #include "compat/socket.h"
65 #include "compat/netinet_in.h"
66 #ifdef HAVE_ARPA_INET_H
67 # include <arpa/inet.h>
68 #endif
69 #include "compat/inet_ntoa.h"
70
71 #include "compat/pdir.h"
72 #include "compat/mkdir.h"
73 #include "d2charfile.h"
74 #include "connection.h"
75 #include "game.h"
76 #include "bnetd.h"
77 #include "d2cs_protocol.h"
78 #include "d2cs_bnetd_protocol.h"
79 #include "handle_d2cs.h"
80 #include "d2ladder.h"
81 #include "gamequeue.h"
82 #include "serverqueue.h"
83 #include "prefs.h"
84 #include "common/bn_type.h"
85 #include "common/queue.h"
86 #include "common/packet.h"
87 #include "common/eventlog.h"
88 #include "d2charlist.h"
89 #include "common/elist.h"
90 #include "common/xalloc.h"
91 #include "common/setup_after.h"
92
93 /* sowater */
94 #include "d2cs_random.h"
95
96 static int d2cs_send_client_ladder(t_connection * c, unsigned char type, unsigned short from);
97 static unsigned int d2cs_try_joingame(t_connection const * c, t_game const * game, char const * gamepass);
98
99 DECLARE_PACKET_HANDLER(on_client_loginreq)
100 DECLARE_PACKET_HANDLER(on_client_createcharreq)
101 DECLARE_PACKET_HANDLER(on_client_creategamereq)
102 DECLARE_PACKET_HANDLER(on_client_joingamereq)
103 DECLARE_PACKET_HANDLER(on_client_gamelistreq)
104 DECLARE_PACKET_HANDLER(on_client_gameinforeq)
105 DECLARE_PACKET_HANDLER(on_client_charloginreq)
106 DECLARE_PACKET_HANDLER(on_client_deletecharreq)
107 DECLARE_PACKET_HANDLER(on_client_ladderreq)
108 DECLARE_PACKET_HANDLER(on_client_motdreq)
109 DECLARE_PACKET_HANDLER(on_client_cancelcreategame)
110 DECLARE_PACKET_HANDLER(on_client_charladderreq)
111 DECLARE_PACKET_HANDLER(on_client_charlistreq)
112 DECLARE_PACKET_HANDLER(on_client_charlistreq_110)
113 DECLARE_PACKET_HANDLER(on_client_convertcharreq)
114
115
116 static t_packet_handle_table d2cs_packet_handle_table[]={
117 /* 0x00 */ { 0, conn_state_none, NULL },
118 /* 0x01 */ { sizeof(t_client_d2cs_loginreq), conn_state_connected, on_client_loginreq },
119 /* 0x02 */ { sizeof(t_client_d2cs_createcharreq), conn_state_authed|conn_state_char_authed, on_client_createcharreq },
120 /* 0x03 */ { sizeof(t_client_d2cs_creategamereq), conn_state_char_authed, on_client_creategamereq },
121 /* 0x04 */ { sizeof(t_client_d2cs_joingamereq), conn_state_char_authed, on_client_joingamereq },
122 /* 0x05 */ { sizeof(t_client_d2cs_gamelistreq), conn_state_char_authed, on_client_gamelistreq },
123 /* 0x06 */ { sizeof(t_client_d2cs_gameinforeq), conn_state_char_authed, on_client_gameinforeq },
124 /* 0x07 */ { sizeof(t_client_d2cs_charloginreq), conn_state_authed|conn_state_char_authed, on_client_charloginreq },
125 /* 0x08 */ { 0, conn_state_none, NULL },
126 /* 0x09 */ { 0, conn_state_none, NULL },
127 /* 0x0a */ { sizeof(t_client_d2cs_deletecharreq), conn_state_authed|conn_state_char_authed, on_client_deletecharreq },
128 /* 0x0b */ { 0, conn_state_none, NULL },
129 /* 0x0c */ { 0, conn_state_none, NULL },
130 /* 0x0d */ { 0, conn_state_none, NULL },
131 /* 0x0e */ { 0, conn_state_none, NULL },
132 /* 0x0f */ { 0, conn_state_none, NULL },
133 /* 0x10 */ { 0, conn_state_none, NULL },
134 /* 0x11 */ { sizeof(t_client_d2cs_ladderreq), conn_state_char_authed, on_client_ladderreq },
135 /* 0x12 */ { sizeof(t_client_d2cs_motdreq), conn_state_char_authed, on_client_motdreq },
136 /* 0x13 */ { sizeof(t_client_d2cs_cancelcreategame),conn_state_char_authed, on_client_cancelcreategame},
137 /* 0x14 */ { 0, conn_state_none, NULL },
138 /* 0x15 */ { 0, conn_state_none, NULL },
139 /* 0x16 */ { sizeof(t_client_d2cs_charladderreq), conn_state_char_authed, on_client_charladderreq },
140 /* 0x17 */ { sizeof(t_client_d2cs_charlistreq), conn_state_authed|conn_state_char_authed, on_client_charlistreq },
141 /* 0x18 */ { sizeof(t_client_d2cs_convertcharreq), conn_state_authed|conn_state_char_authed, on_client_convertcharreq },
142 /* 0x19 */ { sizeof(t_client_d2cs_charlistreq_110), conn_state_authed|conn_state_char_authed, on_client_charlistreq_110 }
143 };
144
145
146 extern int d2cs_handle_d2cs_packet(t_connection * c, t_packet * packet)
147 {
148 return conn_process_packet(c,packet,d2cs_packet_handle_table,NELEMS(d2cs_packet_handle_table));
149 }
150
151 static int on_client_loginreq(t_connection * c, t_packet * packet)
152 {
153 t_packet * bnpacket;
154 char const * account;
155 t_sq * sq;
156 unsigned int sessionnum;
157
158 if (!(account=packet_get_str_const(packet,sizeof(t_client_d2cs_loginreq),MAX_CHARNAME_LEN))) {
159 eventlog(eventlog_level_error,__FUNCTION__,"got bad account name");
160 return -1;
161 }
162 if (d2char_check_acctname(account)<0) {
163 eventlog(eventlog_level_error,__FUNCTION__,"got bad account name");
164 return -1;
165 }
166 if (!bnetd_conn()) {
167 eventlog(eventlog_level_warn,__FUNCTION__,"d2cs is offline with bnetd, login request will be rejected");
168 return -1;
169 }
170 sessionnum=bn_int_get(packet->u.client_d2cs_loginreq.sessionnum);
171 conn_set_bnetd_sessionnum(c,sessionnum);
172 eventlog(eventlog_level_info,__FUNCTION__,"got client (*%s) login request sessionnum=0x%X",account,sessionnum);
173 if ((bnpacket=packet_create(packet_class_d2cs_bnetd))) {
174 if ((sq=sq_create(d2cs_conn_get_sessionnum(c),packet,0))) {
175 packet_set_size(bnpacket,sizeof(t_d2cs_bnetd_accountloginreq));
176 packet_set_type(bnpacket,D2CS_BNETD_ACCOUNTLOGINREQ);
177 bn_int_set(&bnpacket->u.d2cs_bnetd_accountloginreq.h.seqno,sq_get_seqno(sq));
178 bn_int_set(&bnpacket->u.d2cs_bnetd_accountloginreq.seqno,
179 bn_int_get(packet->u.client_d2cs_loginreq.seqno));
180 bn_int_set(&bnpacket->u.d2cs_bnetd_accountloginreq.sessionkey,
181 bn_int_get(packet->u.client_d2cs_loginreq.sessionkey));
182 bn_int_set(&bnpacket->u.d2cs_bnetd_accountloginreq.sessionnum,sessionnum);
183 memcpy(bnpacket->u.d2cs_bnetd_accountloginreq.secret_hash,
184 packet->u.client_d2cs_loginreq.secret_hash,
185 sizeof(bnpacket->u.d2cs_bnetd_accountloginreq.secret_hash));
186 packet_append_string(bnpacket,account);
187 conn_push_outqueue(bnetd_conn(),bnpacket);
188 }
189 packet_del_ref(bnpacket);
190 }
191 return 0;
192 }
193
194 static int on_client_createcharreq(t_connection * c, t_packet * packet)
195 {
196 t_packet * rpacket, * bnpacket;
197 char const * charname;
198 char const * account;
199 char * path;
200 t_pdir * dir;
201 t_sq * sq;
202 unsigned int reply;
203 unsigned short status, class;
204 t_d2charinfo_file data;
205 char checknum;
206 if (!(charname=packet_get_str_const(packet,sizeof(t_client_d2cs_createcharreq),MAX_CHARNAME_LEN))) {
207 eventlog(eventlog_level_error,__FUNCTION__,"got bad character name");
208 return -1;
209 }
210 if (!(account=d2cs_conn_get_account(c))) {
211 eventlog(eventlog_level_error,__FUNCTION__,"missing account for character %s",charname);
212 return -1;
213 }
214 class=bn_short_get(packet->u.client_d2cs_createcharreq.class);
215 status=bn_short_get(packet->u.client_d2cs_createcharreq.status);
216
217 path=xmalloc(strlen(prefs_get_charinfo_dir())+1+strlen(account)+1);
218 d2char_get_infodir_name(path,account);
219 if (!(dir=p_opendir(path))) {
220 eventlog(eventlog_level_info,__FUNCTION__,"(*%s) charinfo directory do not exist, building it",account);
221 p_mkdir(path,S_IRWXU);
222 }
223 else
224 p_closedir(dir);
225 xfree(path);
226
227 /* generate checknum, save it in t_connection, and send it to bnetd, by sowater */
228 do {
229 checknum=d2cs_random_char();
230 }while(d2cs_conn_get_checknum(c)==checknum);
231 d2cs_conn_set_checknum(c,checknum);
232 eventlog(eventlog_level_info,__FUNCTION__,"set checknum %c to connection",checknum);
233
234 if (d2char_create(account,charname,class,status)<0) {
235 eventlog(eventlog_level_warn,__FUNCTION__,"error create character %s for account %s",charname,account);
236 reply=D2CS_CLIENT_CREATECHARREPLY_ALREADY_EXIST;
237 } else if (d2charinfo_load(account,charname,&data)<0) {
238 eventlog(eventlog_level_error,__FUNCTION__,"error loading charinfo for character %s(*%s)",charname,account);
239 reply=D2CS_CLIENT_CREATECHARREPLY_FAILED;
240 } else {
241 eventlog(eventlog_level_info,__FUNCTION__,"character %s(*%s) created",charname,account);
242 reply=D2CS_CLIENT_CREATECHARREPLY_SUCCEED;
243 conn_set_charinfo(c,&data.summary);
244 if ((bnpacket=packet_create(packet_class_d2cs_bnetd))) {
245 if ((sq=sq_create(d2cs_conn_get_sessionnum(c),packet,0))) {
246 packet_set_size(bnpacket,sizeof(t_d2cs_bnetd_charloginreq));
247 packet_set_type(bnpacket,D2CS_BNETD_CHARLOGINREQ);
248 bn_int_set(&bnpacket->u.d2cs_bnetd_charloginreq.h.seqno,sq_get_seqno(sq));
249 bn_int_set(&bnpacket->u.d2cs_bnetd_charloginreq.sessionnum,
250 conn_get_bnetd_sessionnum(c));
251 packet_append_string(bnpacket,charname);
252 packet_append_string(bnpacket,(char const *)&data.portrait);
253
254 /* sowater */
255 packet_append_data(bnpacket,&checknum,sizeof(checknum));
256
257 conn_push_outqueue(bnetd_conn(),bnpacket);
258 }
259 packet_del_ref(bnpacket);
260 }
261 return 0;
262 }
263 if ((rpacket=packet_create(packet_class_d2cs))) {
264 packet_set_size(rpacket,sizeof(t_d2cs_client_createcharreply));
265 packet_set_type(rpacket,D2CS_CLIENT_CREATECHARREPLY);
266 bn_int_set(&rpacket->u.d2cs_client_createcharreply.reply,reply);
267 conn_push_outqueue(c,rpacket);
268 packet_del_ref(rpacket);
269 }
270 return 0;
271 }
272
273 static int on_client_creategamereq(t_connection * c, t_packet * packet)
274 {
275 char const * gamename;
276 char const * gamepass;
277 char const * gamedesc;
278 t_game * game;
279 t_d2gs * gs;
280 t_gq * gq;
281 unsigned int tempflag,gameflag;
282 unsigned int leveldiff, maxchar, difficulty, expansion, hardcore, ladder;
283 unsigned int seqno, reply;
284 unsigned int pos;
285 t_elem * elem;
286
287
288
289 pos=sizeof(t_client_d2cs_creategamereq);
290 if (!(gamename=packet_get_str_const(packet,pos,MAX_GAMENAME_LEN))) {
291 eventlog(eventlog_level_error,__FUNCTION__,"got bad game name");
292 return -1;
293 }
294 pos+=strlen(gamename)+1;
295 if (!(gamepass=packet_get_str_const(packet,pos,MAX_GAMEPASS_LEN))) {
296 eventlog(eventlog_level_error,__FUNCTION__,"got bad game pass");
297 return -1;
298 }
299 pos+=strlen(gamepass)+1;
300 if (!(gamedesc=packet_get_str_const(packet,pos,MAX_GAMEDESC_LEN))) {
301 eventlog(eventlog_level_error,__FUNCTION__,"got bad game desc");
302 return -1;
303 }
304
305 tempflag=bn_int_get(packet->u.client_d2cs_creategamereq.gameflag);
306 leveldiff=bn_byte_get(packet->u.client_d2cs_creategamereq.leveldiff);
307 maxchar=bn_byte_get(packet->u.client_d2cs_creategamereq.maxchar);
308 difficulty=gameflag_get_difficulty(tempflag);
309 if (difficulty > conn_get_charinfo_difficulty(c)) {
310 eventlog(eventlog_level_error,__FUNCTION__,"game difficulty exceed character limit %d %d",difficulty,
311 conn_get_charinfo_difficulty(c));
312 return 0;
313 }
314 expansion=conn_get_charinfo_expansion(c);
315 hardcore=conn_get_charinfo_hardcore(c);
316 ladder=conn_get_charinfo_ladder(c);
317 gameflag=gameflag_create(ladder,expansion,hardcore,difficulty);
318
319 gs = NULL;
320 game = NULL;
321 gq=conn_get_gamequeue(c);
322 if (d2cs_gamelist_find_game(gamename)) {
323 eventlog(eventlog_level_info,__FUNCTION__,"game name %s is already exist in gamelist",gamename);
324 reply=D2CS_CLIENT_CREATEGAMEREPLY_NAME_EXIST;
325
326 /* right checknum? sowater */
327 } else if((prefs_antibot_when_password()==0) && prefs_enable_antibot() && d2cs_conn_verify_checknum(c, *gamedesc)) {
328 eventlog(eventlog_level_info,__FUNCTION__,"checksum %c from packet not match checksum from connection",*gamedesc);
329 reply=D2CS_CLIENT_CREATEGAMEREPLY_FAILED;
330 /* when antibot_when_password is true, by sowater, 20051001 */
331 } else if((strlen(gamepass)!=0) && prefs_antibot_when_password() && prefs_enable_antibot()
332 && d2cs_conn_verify_checknum(c, *gamedesc)) {
333 eventlog(eventlog_level_info,__FUNCTION__,"checksum %c from packet not match checksum from connection",*gamedesc);
334 reply=D2CS_CLIENT_CREATEGAMEREPLY_FAILED;
335 } else if (!gq && gqlist_find_game(gamename)) {
336 eventlog(eventlog_level_info,__FUNCTION__,"game name %s is already exist in game queue",gamename);
337 reply=D2CS_CLIENT_CREATEGAMEREPLY_NAME_EXIST;
338 } else if (!(gs=d2gslist_choose_server(c))) {
339 if (gq) {
340 eventlog(eventlog_level_error,__FUNCTION__,"client %d is already in game queue",d2cs_conn_get_sessionnum(c));
341 conn_set_gamequeue(c,NULL);
342 gq_destroy(gq,&elem);
343 return 0;
344 } else if ((gq=gq_create(d2cs_conn_get_sessionnum(c), packet, gamename))) {
345 conn_set_gamequeue(c,gq);
346 d2cs_send_client_creategamewait(c,gqlist_get_length());
347 return 0;
348 }
349 reply=D2CS_CLIENT_CREATEGAMEREPLY_FAILED;
350 } else if (hardcore && conn_get_charinfo_dead(c)) {
351 reply=D2CS_CLIENT_CREATEGAMEREPLY_FAILED;
352 } else if (!(game=d2cs_game_create(gamename,gamepass,gamedesc,gameflag))) {
353 reply=D2CS_CLIENT_CREATEGAMEREPLY_NAME_EXIST;
354 } else {
355 reply=D2CS_CLIENT_CREATEGAMEREPLY_SUCCEED;
356 game_set_d2gs(game,gs);
357 d2gs_add_gamenum(gs, 1);
358 game_set_gameflag_ladder(game,ladder);
359 game_set_gameflag_expansion(game,expansion);
360 game_set_created(game,0);
361 game_set_leveldiff(game,leveldiff);
362 game_set_charlevel(game,conn_get_charinfo_level(c));
363 game_set_maxchar(game,maxchar);
364 game_set_gameflag_difficulty(game,difficulty);
365 game_set_gameflag_hardcore(game,hardcore);
366 }
367
368 seqno=bn_short_get(packet->u.client_d2cs_creategamereq.seqno);
369 if (reply!=D2CS_CLIENT_CREATEGAMEREPLY_SUCCEED) {
370 t_packet * rpacket;
371
372 if ((rpacket=packet_create(packet_class_d2cs))) {
373 packet_set_size(rpacket,sizeof(t_d2cs_client_creategamereply));
374 packet_set_type(rpacket,D2CS_CLIENT_CREATEGAMEREPLY);
375 bn_short_set(&rpacket->u.d2cs_client_creategamereply.seqno,seqno);
376 bn_short_set(&rpacket->u.d2cs_client_creategamereply.u1,0);
377 bn_short_set(&rpacket->u.d2cs_client_creategamereply.gameid,0);
378 bn_int_set(&rpacket->u.d2cs_client_creategamereply.reply,reply);
379 conn_push_outqueue(c,rpacket);
380 packet_del_ref(rpacket);
381 }
382 } else {
383 t_packet * gspacket;
384 t_sq * sq;
385 struct in_addr addr;
386
387 if ((gspacket=packet_create(packet_class_d2gs))) {
388 if ((sq=sq_create(d2cs_conn_get_sessionnum(c),packet,d2cs_game_get_id(game)))) {
389 packet_set_size(gspacket,sizeof(t_d2cs_d2gs_creategamereq));
390 packet_set_type(gspacket,D2CS_D2GS_CREATEGAMEREQ);
391 bn_int_set(&gspacket->u.d2cs_d2gs_creategamereq.h.seqno,sq_get_seqno(sq));
392 bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.difficulty,difficulty);
393 bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.hardcore,hardcore);
394 bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.expansion,expansion);
395 bn_byte_set(&gspacket->u.d2cs_d2gs_creategamereq.ladder,ladder);
396 packet_append_string(gspacket,gamename);
397 packet_append_string(gspacket,gamepass);
398 packet_append_string(gspacket,gamedesc);
399 packet_append_string(gspacket,d2cs_conn_get_account(c));
400 packet_append_string(gspacket,d2cs_conn_get_charname(c));
401 addr.s_addr = htonl(d2cs_conn_get_addr(c));
402 packet_append_string(gspacket,inet_ntoa(addr));
403 conn_push_outqueue(d2gs_get_connection(gs),gspacket);
404 }
405 packet_del_ref(gspacket);
406 eventlog(eventlog_level_info,__FUNCTION__,"request create game %s on gs %d",gamename,d2gs_get_id(gs));
407 }
408 }
409 return 0;
410 }
411
412 static int on_client_joingamereq(t_connection * c, t_packet * packet)
413 {
414 char const * gamename;
415 char const * gamepass;
416 char const * charname;
417 char const * account;
418 t_game * game;
419 t_d2gs * gs;
420 int reply;
421 unsigned int pos;
422 unsigned int seqno;
423
424 gs = NULL;
425 pos=sizeof(t_client_d2cs_joingamereq);
426 if (!(gamename=packet_get_str_const(packet,pos,MAX_GAMENAME_LEN))) {
427 eventlog(eventlog_level_error,__FUNCTION__,"got bad game name");
428 return -1;
429 }
430 pos+=strlen(gamename)+1;
431 if (!(gamepass=packet_get_str_const(packet,pos,MAX_GAMEPASS_LEN))) {
432 eventlog(eventlog_level_error,__FUNCTION__,"got bad game pass");
433 return -1;
434 }
435 if (!(charname=d2cs_conn_get_charname(c))) {
436 eventlog(eventlog_level_error,__FUNCTION__,"missing character name for connection");
437 return -1;
438 }
439 if (!(account=d2cs_conn_get_account(c))) {
440 eventlog(eventlog_level_error,__FUNCTION__,"missing account for connection");
441 return -1;
442 }
443 if (conn_check_multilogin(c,charname)<0) {
444 eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname);
445 return -1;
446 }
447 if (!(game=d2cs_gamelist_find_game(gamename))) {
448 eventlog(eventlog_level_info,__FUNCTION__,"game %s not found",gamename);
449 reply=D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST;
450 } else if (!(gs=game_get_d2gs(game))) {
451 eventlog(eventlog_level_error,__FUNCTION__,"missing game server for game %s",gamename);
452 reply=D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST;
453 } else {
454 reply=d2cs_try_joingame(c,game,gamepass);
455 }
456
457 seqno=bn_short_get(packet->u.client_d2cs_joingamereq.seqno);
458 if (reply!=D2CS_CLIENT_JOINGAMEREPLY_SUCCEED) {
459 t_packet * rpacket;
460
461 if ((rpacket=packet_create(packet_class_d2cs))) {
462 packet_set_size(rpacket,sizeof(t_d2cs_client_joingamereply));
463 packet_set_type(rpacket,D2CS_CLIENT_JOINGAMEREPLY);
464 bn_short_set(&rpacket->u.d2cs_client_joingamereply.seqno,seqno);
465 bn_short_set(&rpacket->u.d2cs_client_joingamereply.u1,0);
466 bn_short_set(&rpacket->u.d2cs_client_joingamereply.gameid,0);
467 bn_int_set(&rpacket->u.d2cs_client_joingamereply.addr,0);
468 bn_int_set(&rpacket->u.d2cs_client_joingamereply.token,0);
469 bn_int_set(&rpacket->u.d2cs_client_joingamereply.reply,reply);
470 conn_push_outqueue(c,rpacket);
471 packet_del_ref(rpacket);
472 }
473 } else {
474 t_packet * gspacket;
475 t_sq * sq;
476 struct in_addr addr;
477
478 if ((gspacket=packet_create(packet_class_d2gs))) {
479 if ((sq=sq_create(d2cs_conn_get_sessionnum(c),packet,d2cs_game_get_id(game)))) {
480 packet_set_size(gspacket,sizeof(t_d2cs_d2gs_joingamereq));
481 packet_set_type(gspacket,D2CS_D2GS_JOINGAMEREQ);
482 bn_int_set(&gspacket->u.d2cs_d2gs_joingamereq.h.seqno,sq_get_seqno(sq));
483 bn_int_set(&gspacket->u.d2cs_d2gs_joingamereq.gameid,
484 game_get_d2gs_gameid(game));
485 sq_set_gametoken(sq,d2gs_make_token(gs));
486 bn_int_set(&gspacket->u.d2cs_d2gs_joingamereq.token,sq_get_gametoken(sq));
487 packet_append_string(gspacket,charname);
488 packet_append_string(gspacket,account);
489 addr.s_addr = htonl(d2cs_conn_get_addr(c));
490 packet_append_string(gspacket,inet_ntoa(addr));
491 conn_push_outqueue(d2gs_get_connection(gs),gspacket);
492 }
493 packet_del_ref(gspacket);
494 eventlog(eventlog_level_info,__FUNCTION__,"request join game %s for character %s on gs %d",gamename,
495 charname,d2gs_get_id(gs));
496 }
497 }
498 return 0;
499 }
500
501 static int on_client_gamelistreq(t_connection * c, t_packet * packet)
502 {
503 t_packet * rpacket;
504 t_game * game;
505 unsigned int count;
506 unsigned int seqno;
507 time_t now;
508 unsigned int maxlifetime;
509 t_elem const * start_elem;
510 t_elem const * elem;
511
512 seqno=bn_short_get(packet->u.client_d2cs_gamelistreq.seqno);
513 /* if (seqno%2) return 0; */
514 count=0;
515 now=time(NULL);
516 maxlifetime=prefs_get_game_maxlifetime();
517
518 elem=start_elem=gamelist_get_curr_elem();
519 if (!elem) elem=list_get_first_const(d2cs_gamelist());
520 else elem=elem_get_next_const(d2cs_gamelist(),elem);
521
522 for (; elem != start_elem; elem=elem_get_next_const(d2cs_gamelist(),elem)) {
523 if (!elem) {
524 elem=list_get_first_const(d2cs_gamelist());
525 if (elem == start_elem) break;
526 }
527 if (!(game=elem_get_data(elem))) {
528 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
529 break;
530 }
531 if (maxlifetime && (now-game->create_time>maxlifetime)) continue;
532 if (!game_get_currchar(game)) continue;
533 if (!prefs_allow_gamelist_showall()) {
534 if (conn_get_charinfo_difficulty(c)!=game_get_gameflag_difficulty(game)) continue;
535 }
536 if (d2cs_try_joingame(c,game,"")!=D2CS_CLIENT_JOINGAMEREPLY_SUCCEED) continue;
537 if ((rpacket=packet_create(packet_class_d2cs))) {
538 packet_set_size(rpacket,sizeof(t_d2cs_client_gamelistreply));
539 packet_set_type(rpacket,D2CS_CLIENT_GAMELISTREPLY);
540 bn_short_set(&rpacket->u.d2cs_client_gamelistreply.seqno,seqno);
541 bn_int_set(&rpacket->u.d2cs_client_gamelistreply.token,d2cs_game_get_id(game));
542 bn_byte_set(&rpacket->u.d2cs_client_gamelistreply.currchar,game_get_currchar(game));
543 bn_int_set(&rpacket->u.d2cs_client_gamelistreply.gameflag,game_get_gameflag(game));
544 packet_append_string(rpacket,d2cs_game_get_name(game));
545 packet_append_string(rpacket,game_get_desc(game));
546 conn_push_outqueue(c,rpacket);
547 packet_del_ref(rpacket);
548 count++;
549 if (prefs_get_maxgamelist() && count>=prefs_get_maxgamelist()) break;
550 }
551 }
552 gamelist_set_curr_elem(elem);
553 if (count) {
554 if ((rpacket=packet_create(packet_class_d2cs))) {
555 packet_set_size(rpacket,sizeof(t_d2cs_client_gamelistreply));
556 packet_set_type(rpacket,D2CS_CLIENT_GAMELISTREPLY);
557 bn_short_set(&rpacket->u.d2cs_client_gamelistreply.seqno,seqno);
558 bn_int_set(&rpacket->u.d2cs_client_gamelistreply.token,0);
559 bn_byte_set(&rpacket->u.d2cs_client_gamelistreply.currchar,0);
560 bn_int_set(&rpacket->u.d2cs_client_gamelistreply.gameflag,0);
561 packet_append_string(rpacket,"");
562 packet_append_string(rpacket,"");
563 packet_append_string(rpacket,"");
564 conn_push_outqueue(c,rpacket);
565 packet_del_ref(rpacket);
566 }
567 }
568 return 0;
569 }
570
571 static int on_client_gameinforeq(t_connection * c, t_packet * packet)
572 {
573 t_game_charinfo * info;
574 t_packet * rpacket;
575 char const * gamename;
576 t_game * game;
577 unsigned int seqno, n;
578
579 if (!(gamename=packet_get_str_const(packet,sizeof(t_client_d2cs_gameinforeq),MAX_GAMENAME_LEN))) {
580 eventlog(eventlog_level_error,__FUNCTION__,"got bad game name");
581 return -1;
582 }
583 if (!(game=d2cs_gamelist_find_game(gamename))) {
584 eventlog(eventlog_level_error,__FUNCTION__,"game %s not found",gamename);
585 return 0;
586 }
587 seqno=bn_short_get(packet->u.client_d2cs_gameinforeq.seqno);
588 if ((rpacket=packet_create(packet_class_d2cs))) {
589 packet_set_size(rpacket,sizeof(t_d2cs_client_gameinforeply));
590 packet_set_type(rpacket,D2CS_CLIENT_GAMEINFOREPLY);
591 bn_short_set(&rpacket->u.d2cs_client_gameinforeply.seqno,seqno);
592 bn_int_set(&rpacket->u.d2cs_client_gameinforeply.gameflag,game_get_gameflag(game));
593 bn_int_set(&rpacket->u.d2cs_client_gameinforeply.etime,time(NULL)-d2cs_game_get_create_time(game));
594 bn_byte_set(&rpacket->u.d2cs_client_gameinforeply.charlevel,game_get_charlevel(game));
595 bn_byte_set(&rpacket->u.d2cs_client_gameinforeply.leveldiff,game_get_leveldiff(game));
596 bn_byte_set(&rpacket->u.d2cs_client_gameinforeply.maxchar,game_get_maxchar(game));
597 packet_append_string(rpacket, game_get_desc(game) ? game_get_desc(game) : NULL);
598
599 n=0;
600 BEGIN_LIST_TRAVERSE_DATA_CONST(game_get_charlist(game),info)
601 {
602 if (!info->charname) {
603 eventlog(eventlog_level_error,__FUNCTION__,"got NULL charname in game %s char list",gamename);
604 continue;
605 }
606 packet_append_string(rpacket,info->charname);
607 bn_byte_set(&rpacket->u.d2cs_client_gameinforeply.class[n],info->class);
608 bn_byte_set(&rpacket->u.d2cs_client_gameinforeply.level[n],info->level);
609 n++;
610 }
611 END_LIST_TRAVERSE_DATA_CONST()
612
613 bn_byte_set(&rpacket->u.d2cs_client_gameinforeply.currchar,n);
614 if (n!=game_get_currchar(game)) {
615 eventlog(eventlog_level_error,__FUNCTION__,"game %s character list corrupted",gamename);
616 }
617 conn_push_outqueue(c,rpacket);
618 packet_del_ref(rpacket);
619 }
620 return 0;
621 }
622
623 static int on_client_charloginreq(t_connection * c, t_packet * packet)
624 {
625 t_packet * bnpacket;
626 char const * charname;
627 char const * account;
628 t_sq * sq;
629 t_d2charinfo_file data;
630 unsigned int expire_time;
631 char checknum;
632
633 if (!(charname=packet_get_str_const(packet,sizeof(t_client_d2cs_charloginreq),MAX_CHARNAME_LEN))) {
634 eventlog(eventlog_level_error,__FUNCTION__,"got bad character name");
635 return -1;
636 }
637 if (!(account=d2cs_conn_get_account(c))) {
638 eventlog(eventlog_level_error,__FUNCTION__,"missing account for connection");
639 return -1;
640 }
641 if (d2charinfo_load(account,charname,&data)<0) {
642 eventlog(eventlog_level_error,__FUNCTION__,"error loading charinfo for character %s(*%s)",charname,account);
643 return -1;
644 } else if (!bnetd_conn()) {
645 eventlog(eventlog_level_error,__FUNCTION__,"no bnetd connection available,character login rejected");
646 return -1;
647 }
648 expire_time = prefs_get_char_expire_time();
649 if (expire_time && (time(NULL) > bn_int_get(data.header.last_time) + expire_time)) {
650 t_packet * rpacket;
651
652 if ((rpacket=packet_create(packet_class_d2cs))) {
653 packet_set_size(rpacket,sizeof(t_d2cs_client_charloginreply));
654 packet_set_type(rpacket,D2CS_CLIENT_CHARLOGINREPLY);
655 bn_int_set(&rpacket->u.d2cs_client_charloginreply.reply, D2CS_CLIENT_CHARLOGINREPLY_EXPIRED);
656 conn_push_outqueue(c,rpacket);
657 packet_del_ref(rpacket);
658 }
659 eventlog(eventlog_level_info,__FUNCTION__,"character %s(*%s) login rejected due to char expired",charname,account);
660 return 0;
661 }
662
663 conn_set_charinfo(c,&data.summary);
664 eventlog(eventlog_level_info,__FUNCTION__,"got character %s(*%s) login request",charname,account);
665
666 /* generate checknum, save it in t_connection, and send it to bnetd, by sowater */
667 do {
668 checknum=d2cs_random_char();
669 }while(d2cs_conn_get_checknum(c)==checknum);
670 d2cs_conn_set_checknum(c,checknum);
671 eventlog(eventlog_level_info,__FUNCTION__,"set checknum %c to connection",checknum);
672
673 if ((bnpacket=packet_create(packet_class_d2cs_bnetd))) {
674 if ((sq=sq_create(d2cs_conn_get_sessionnum(c),packet,0))) {
675 packet_set_size(bnpacket,sizeof(t_d2cs_bnetd_charloginreq));
676 packet_set_type(bnpacket,D2CS_BNETD_CHARLOGINREQ);
677 bn_int_set(&bnpacket->u.d2cs_bnetd_charloginreq.h.seqno,sq_get_seqno(sq));
678 bn_int_set(&bnpacket->u.d2cs_bnetd_charloginreq.sessionnum,
679 conn_get_bnetd_sessionnum(c));
680 packet_append_string(bnpacket,charname);
681 packet_append_string(bnpacket,(char const *)&data.portrait);
682
683 /*sowater */
684 packet_append_data(bnpacket,&checknum,sizeof(checknum));
685
686 conn_push_outqueue(bnetd_conn(),bnpacket);
687 }
688 packet_del_ref(bnpacket);
689 }
690 return 0;
691 }
692
693 static int on_client_deletecharreq(t_connection * c, t_packet * packet)
694 {
695 t_packet * rpacket;
696 char const * charname;
697 char const * account;
698 unsigned int reply;
699
700 if (!(charname=packet_get_str_const(packet,sizeof(t_client_d2cs_deletecharreq),MAX_CHARNAME_LEN))) {
701 eventlog(eventlog_level_error,__FUNCTION__,"got bad character name");
702 return -1;
703 }
704 if (conn_check_multilogin(c,charname)<0) {
705 eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname);
706 return -1;
707 }
708 d2cs_conn_set_charname(c,NULL);
709 account=d2cs_conn_get_account(c);
710 if (d2char_delete(account,charname)<0) {
711 eventlog(eventlog_level_error,__FUNCTION__,"failed to delete character %s(*%s)",charname,account);
712 reply = D2CS_CLIENT_DELETECHARREPLY_FAILED;
713 } else {
714 reply = D2CS_CLIENT_DELETECHARREPLY_SUCCEED;
715 }
716 if ((rpacket=packet_create(packet_class_d2cs))) {
717 packet_set_size(rpacket,sizeof(t_d2cs_client_deletecharreply));
718 packet_set_type(rpacket,D2CS_CLIENT_DELETECHARREPLY);
719 bn_short_set(&rpacket->u.d2cs_client_deletecharreply.u1,0);
720 bn_int_set(&rpacket->u.d2cs_client_deletecharreply.reply,reply);
721 conn_push_outqueue(c,rpacket);
722 packet_del_ref(rpacket);
723 }
724 return 0;
725 }
726
727 static int on_client_ladderreq(t_connection * c, t_packet * packet)
728 {
729 unsigned char type;
730 unsigned short start_pos;
731
732 type=bn_byte_get(packet->u.client_d2cs_ladderreq.type);
733 start_pos=bn_short_get(packet->u.client_d2cs_ladderreq.start_pos);
734 d2cs_send_client_ladder(c,type,start_pos);
735 return 0;
736 }
737
738 static int d2cs_send_client_ladder(t_connection * c, unsigned char type, unsigned short from)
739 {
740 t_packet * rpacket;
741 t_d2cs_client_ladderinfo const * ladderinfo;
742 unsigned int curr_len, cont_len, total_len;
743 t_d2cs_client_ladderheader ladderheader;
744 t_d2cs_client_ladderinfoheader infoheader;
745 unsigned int start_pos, count, count_per_packet, npacket;
746 unsigned int i, n, curr_pos;
747
748 start_pos=from;
749 count=prefs_get_ladderlist_count();
750 if (d2ladder_get_ladder(&start_pos,&count,type,&ladderinfo)<0) {
751 eventlog(eventlog_level_error,__FUNCTION__,"error get ladder for type %d start_pos %d",type,from);
752 return 0;
753 }
754
755 count_per_packet=14;
756 npacket=count/count_per_packet;
757 if (count % count_per_packet) npacket++;
758
759 curr_len=0;
760 cont_len=0;
761 total_len = count * sizeof(*ladderinfo) + sizeof(ladderheader) + sizeof(infoheader) * npacket;
762 total_len -= 4;
763 bn_short_set(&ladderheader.start_pos,start_pos);
764 bn_short_set(&ladderheader.u1,0);
765 bn_int_set(&ladderheader.count1,count);
766
767 for (i=0; i< npacket; i++) {
768 curr_len=0;
769 if ((rpacket=packet_create(packet_class_d2cs))) {
770 packet_set_size(rpacket,sizeof(t_d2cs_client_ladderreply));
771 packet_set_type(rpacket,D2CS_CLIENT_LADDERREPLY);
772 bn_byte_set(&rpacket->u.d2cs_client_ladderreply.type, type);
773 bn_short_set(&rpacket->u.d2cs_client_ladderreply.total_len, total_len);
774 bn_short_set(&rpacket->u.d2cs_client_ladderreply.cont_len,cont_len);
775 if (i==0) {
776 bn_int_set(&infoheader.count2,count);
777 packet_append_data(rpacket,&ladderheader,sizeof(ladderheader));
778 curr_len += sizeof(ladderheader);
779 } else {
780 bn_int_set(&infoheader.count2,0);
781 }
782 packet_append_data(rpacket,&infoheader,sizeof(infoheader));
783 curr_len += sizeof(infoheader);
784 for (n=0; n< count_per_packet; n++) {
785 curr_pos = n + i * count_per_packet;
786 if (curr_pos >= count) break;
787 packet_append_data(rpacket, ladderinfo+curr_pos, sizeof(*ladderinfo));
788 curr_len += sizeof(*ladderinfo);
789 }
790 if (i==0) {
791 packet_set_size(rpacket, packet_get_size(rpacket)-4);
792 curr_len -= 4;
793 }
794 bn_short_set(&rpacket->u.d2cs_client_ladderreply.curr_len,curr_len);
795 conn_push_outqueue(c,rpacket);
796 packet_del_ref(rpacket);
797 }
798 cont_len += curr_len;
799 }
800 return 0;
801 }
802
803 static int on_client_motdreq(t_connection * c, t_packet * packet)
804 {
805 t_packet * rpacket;
806
807 if (!packet)
808 return -1;
809
810 if ((rpacket=packet_create(packet_class_d2cs))) {
811 packet_set_size(rpacket,sizeof(t_d2cs_client_motdreply));
812 packet_set_type(rpacket,D2CS_CLIENT_MOTDREPLY);
813 bn_byte_set(&rpacket->u.d2cs_client_motdreply.u1,0);
814 packet_append_string(rpacket,prefs_get_motd());
815 conn_push_outqueue(c,rpacket);
816 packet_del_ref(rpacket);
817 }
818 return 0;
819 }
820
821 static int on_client_cancelcreategame(t_connection * c, t_packet * packet)
822 {
823 t_gq * gq;
824 t_elem * elem;
825
826 if (!packet)
827 return -1;
828
829 if (!(gq=conn_get_gamequeue(c))) {
830 return 0;
831 }
832 conn_set_gamequeue(c,NULL);
833 gq_destroy(gq,&elem);
834 return 0;
835 }
836
837 static int on_client_charladderreq(t_connection * c, t_packet * packet)
838 {
839 t_packet * rpacket;
840 char const * charname;
841 unsigned int expansion, hardcore, type;
842 int pos;
843
844 if (!(charname=packet_get_str_const(packet,sizeof(t_client_d2cs_charladderreq),MAX_CHARNAME_LEN))) {
845 eventlog(eventlog_level_error,__FUNCTION__,"got bad character name");
846 return -1;
847 }
848 expansion=bn_int_get(packet->u.client_d2cs_charladderreq.expansion);
849 hardcore=bn_int_get(packet->u.client_d2cs_charladderreq.hardcore);
850 type=0; /* avoid warning */
851 if (hardcore && expansion) {
852 type=D2LADDER_EXP_HC_OVERALL;
853 } else if (!hardcore && expansion) {
854 type=D2LADDER_EXP_STD_OVERALL;
855 } else if (hardcore && !expansion) {
856 type=D2LADDER_HC_OVERALL;
857 } else if (!hardcore && !expansion) {
858 type=D2LADDER_STD_OVERALL;
859 }
860 if ((pos=d2ladder_find_character_pos(type,charname))<0) {
861 if ((rpacket=packet_create(packet_class_d2cs))) {
862 packet_set_size(rpacket,sizeof(t_d2cs_client_ladderreply));
863 packet_set_type(rpacket,D2CS_CLIENT_LADDERREPLY);
864 bn_byte_set(&rpacket->u.d2cs_client_ladderreply.type, type);
865 bn_short_set(&rpacket->u.d2cs_client_ladderreply.total_len,0);
866 bn_short_set(&rpacket->u.d2cs_client_ladderreply.curr_len,0);
867 bn_short_set(&rpacket->u.d2cs_client_ladderreply.cont_len,0);
868 conn_push_outqueue(c,rpacket);
869 packet_del_ref(rpacket);
870 }
871 return 0;
872 }
873 pos -= prefs_get_ladderlist_count()/2;
874 if (pos < 0) pos=0;
875 d2cs_send_client_ladder(c,type,pos);
876 return 0;
877 }
878
879 static int on_client_charlistreq(t_connection * c, t_packet * packet)
880 {
881 t_packet * rpacket;
882 t_pdir * dir;
883 char const * account;
884 char const * charname;
885 char * path;
886 t_d2charinfo_file * charinfo;
887 unsigned int n, maxchar;
888 t_elist charlist_head;
889 char const * charlist_sort_order;
890
891 if (!packet)
892 return -1;
893
894 if (!(account=d2cs_conn_get_account(c))) {
895 eventlog(eventlog_level_error,__FUNCTION__,"missing account for connection");
896 return -1;
897 }
898 path=xmalloc(strlen(prefs_get_charinfo_dir())+1+strlen(account)+1);
899 charlist_sort_order = prefs_get_charlist_sort_order();
900
901 elist_init(&charlist_head);
902
903 d2char_get_infodir_name(path,account);
904 maxchar=prefs_get_maxchar();
905 if ((rpacket=packet_create(packet_class_d2cs))) {
906 packet_set_size(rpacket,sizeof(t_d2cs_client_charlistreply));
907 packet_set_type(rpacket,D2CS_CLIENT_CHARLISTREPLY);
908 bn_short_set(&rpacket->u.d2cs_client_charlistreply.u1,0);
909 n=0;
910 if (!(dir=p_opendir(path))) {
911 eventlog(eventlog_level_info,__FUNCTION__,"(*%s) charinfo directory do not exist, building it",account);
912 p_mkdir(path,S_IRWXU);
913 } else {
914 while ((charname=p_readdir(dir))) {
915 if (charname[0]=='.') continue;
916 charinfo = xmalloc(sizeof(t_d2charinfo_file));
917 if (d2charinfo_load(account,charname,charinfo)<0) {
918 eventlog(eventlog_level_error,__FUNCTION__,"error loading charinfo for %s(*%s)",charname,account);
919 xfree((void *)charinfo);
920 continue;
921 }
922 eventlog(eventlog_level_debug,__FUNCTION__,"adding char %s (*%s)", charname, account);
923 d2charlist_add_char(&charlist_head,charinfo,0);
924 n++;
925 if (n>=maxchar) break;
926 }
927 if (prefs_allow_newchar() && (n<maxchar)) {
928 bn_short_set(&rpacket->u.d2cs_client_charlistreply.maxchar,maxchar);
929 } else {
930 bn_short_set(&rpacket->u.d2cs_client_charlistreply.maxchar,0);
931 }
932 p_closedir(dir);
933 if (!strcmp(charlist_sort_order, "ASC"))
934 {
935 t_elist * curr, * safe;
936 t_d2charlist * ccharlist;
937
938 elist_for_each_safe(curr,&charlist_head,safe)
939 {
940 ccharlist = elist_entry(curr,t_d2charlist,list);
941 packet_append_string(rpacket,ccharlist->charinfo->header.charname);
942 packet_append_string(rpacket,(char *)&ccharlist->charinfo->portrait);
943 xfree((void *)ccharlist->charinfo);
944 xfree((void *)ccharlist);
945 }
946 }
947 else
948 {
949 t_elist * curr, * safe;
950 t_d2charlist * ccharlist;
951
952 elist_for_each_safe_rev(curr,&charlist_head,safe)
953 {
954 ccharlist = elist_entry(curr,t_d2charlist,list);
955 packet_append_string(rpacket,ccharlist->charinfo->header.charname);
956 packet_append_string(rpacket,(char *)&ccharlist->charinfo->portrait);
957 xfree((void *)ccharlist->charinfo);
958 xfree((void *)ccharlist);
959
960 }
961 }
962 }
963 bn_short_set(&rpacket->u.d2cs_client_charlistreply.currchar,n);
964 bn_short_set(&rpacket->u.d2cs_client_charlistreply.currchar2,n);
965 conn_push_outqueue(c,rpacket);
966 packet_del_ref(rpacket);
967 }
968 xfree(path);
969 return 0;
970 }
971
972 static int on_client_charlistreq_110(t_connection * c, t_packet * packet)
973 {
974 t_packet * rpacket;
975 t_pdir * dir;
976 char const * account;
977 char const * charname;
978 char * path;
979
980 t_d2charinfo_file * charinfo;
981 unsigned int n, maxchar;
982 t_elist charlist_head;
983
984 unsigned int exp_time;
985 unsigned int curr_exp_time;
986 char const * charlist_sort_order;
987
988 if (!packet)
989 return -1;
990
991 if (!(account=d2cs_conn_get_account(c))) {
992 eventlog(eventlog_level_error,__FUNCTION__,"missing account for connection");
993 return -1;
994 }
995 path=xmalloc(strlen(prefs_get_charinfo_dir())+1+strlen(account)+1);
996 charlist_sort_order = prefs_get_charlist_sort_order();
997
998 elist_init(&charlist_head);
999
1000 d2char_get_infodir_name(path,account);
1001 if (prefs_allow_newchar())
1002 maxchar=prefs_get_maxchar();
1003 else
1004 maxchar=0;
1005
1006 if ((rpacket=packet_create(packet_class_d2cs))) {
1007 packet_set_size(rpacket,sizeof(t_d2cs_client_charlistreply_110));
1008 packet_set_type(rpacket,D2CS_CLIENT_CHARLISTREPLY_110);
1009 bn_short_set(&rpacket->u.d2cs_client_charlistreply_110.u1,0);
1010 n=0;
1011 if (!(dir=p_opendir(path))) {
1012 eventlog(eventlog_level_info,__FUNCTION__,"(*%s) charinfo directory do not exist, building it",account);
1013 p_mkdir(path,S_IRWXU);
1014 } else {
1015 exp_time = prefs_get_char_expire_time();
1016 while ((charname=p_readdir(dir))) {
1017 if (charname[0]=='.') continue;
1018 charinfo = xmalloc(sizeof(t_d2charinfo_file));
1019 if (d2charinfo_load(account,charname,charinfo)<0) {
1020 eventlog(eventlog_level_error,__FUNCTION__,"error loading charinfo for %s(*%s)",charname,account);
1021 xfree(charinfo);
1022 continue;
1023 }
1024 if (exp_time) {
1025 curr_exp_time = bn_int_get(charinfo->header.last_time)+exp_time;
1026 } else {
1027 curr_exp_time = 0x7FFFFFFF;
1028 }
1029 eventlog(eventlog_level_debug,__FUNCTION__,"adding char %s (*%s)", charname, account);
1030 d2charlist_add_char(&charlist_head,charinfo,curr_exp_time);
1031 n++;
1032 if (n>=maxchar) break;
1033 }
1034 if (n>=maxchar)
1035 maxchar = 0;
1036
1037 p_closedir(dir);
1038 if (!strcmp(charlist_sort_order, "ASC"))
1039 {
1040 t_elist * curr, *safe;
1041 t_d2charlist * ccharlist;
1042
1043 elist_for_each_safe(curr,&charlist_head,safe)
1044 {
1045 bn_int bn_exp_time;
1046
1047 ccharlist = elist_entry(curr,t_d2charlist,list);
1048 bn_int_set(&bn_exp_time,ccharlist->expiration_time);
1049 packet_append_data(rpacket,bn_exp_time,sizeof(bn_exp_time));
1050 packet_append_string(rpacket,ccharlist->charinfo->header.charname);
1051 packet_append_string(rpacket,(char *)&ccharlist->charinfo->portrait);
1052 xfree((void *)ccharlist->charinfo);
1053 xfree((void *)ccharlist);
1054 }
1055 }
1056 else
1057 {
1058 t_elist * curr, *safe;
1059 t_d2charlist * ccharlist;
1060
1061 elist_for_each_safe_rev(curr,&charlist_head,safe)
1062 {
1063 bn_int bn_exp_time;
1064
1065 ccharlist = elist_entry(curr,t_d2charlist,list);
1066 bn_int_set(&bn_exp_time,ccharlist->expiration_time);
1067 packet_append_data(rpacket,bn_exp_time,sizeof(bn_exp_time));
1068 packet_append_string(rpacket,ccharlist->charinfo->header.charname);
1069 packet_append_string(rpacket,(char *)&ccharlist->charinfo->portrait);
1070 xfree((void *)ccharlist->charinfo);
1071 xfree((void *)ccharlist);
1072 }
1073 }
1074 }
1075 bn_short_set(&rpacket->u.d2cs_client_charlistreply.currchar,n);
1076 bn_short_set(&rpacket->u.d2cs_client_charlistreply.currchar2,n);
1077 bn_short_set(&rpacket->u.d2cs_client_charlistreply.maxchar,maxchar);
1078
1079 conn_push_outqueue(c,rpacket);
1080 packet_del_ref(rpacket);
1081 }
1082 xfree(path);
1083 return 0;
1084 }
1085
1086 static int on_client_convertcharreq(t_connection * c, t_packet * packet)
1087 {
1088 t_packet * rpacket;
1089 char const * charname;
1090 char const * account;
1091 unsigned int reply;
1092
1093 if (!(charname=packet_get_str_const(packet,sizeof(t_client_d2cs_convertcharreq),MAX_CHARNAME_LEN))) {
1094 eventlog(eventlog_level_error,__FUNCTION__,"got bad character name");
1095 return -1;
1096 }
1097 if (conn_check_multilogin(c,charname)<0) {
1098 eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname);
1099 return -1;
1100 }
1101 account=d2cs_conn_get_account(c);
1102 if (d2char_convert(account,charname)<0) {
1103 eventlog(eventlog_level_error,__FUNCTION__,"failed to convert character %s(*%s)",charname,account);
1104 reply = D2CS_CLIENT_CONVERTCHARREPLY_FAILED;
1105 } else {
1106 reply = D2CS_CLIENT_CONVERTCHARREPLY_SUCCEED;
1107 }
1108 if ((rpacket=packet_create(packet_class_d2cs))) {
1109 packet_set_size(rpacket,sizeof(t_d2cs_client_convertcharreply));
1110 packet_set_type(rpacket,D2CS_CLIENT_CONVERTCHARREPLY);
1111 bn_int_set(&rpacket->u.d2cs_client_convertcharreply.reply,reply);
1112 conn_push_outqueue(c,rpacket);
1113 packet_del_ref(rpacket);
1114 }
1115 return 0;
1116 }
1117
1118 extern int d2cs_send_client_creategamewait(t_connection * c, unsigned int position)
1119 {
1120 t_packet * packet;
1121
1122 ASSERT(c,-1);
1123 if ((packet=packet_create(packet_class_d2cs))) {
1124 packet_set_size(packet,sizeof(t_d2cs_client_creategamewait));
1125 packet_set_type(packet,D2CS_CLIENT_CREATEGAMEWAIT);
1126 bn_int_set(&packet->u.d2cs_client_creategamewait.position,position);
1127 conn_push_outqueue(c,packet);
1128 packet_del_ref(packet);
1129 }
1130 return 0;
1131 }
1132
1133 extern int d2cs_handle_client_creategame(t_connection * c, t_packet * packet)
1134 {
1135 return on_client_creategamereq(c,packet);
1136 }
1137
1138 static unsigned int d2cs_try_joingame(t_connection const * c, t_game const * game, char const * gamepass)
1139 {
1140 unsigned int reply;
1141
1142 ASSERT(c,D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST);
1143 ASSERT(game,D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST);
1144 if (!game_get_created(game)) {
1145 reply=D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST;
1146 } else if (!game_get_d2gs(game)) {
1147 reply=D2CS_CLIENT_JOINGAMEREPLY_NOT_EXIST;
1148 } else if (conn_get_charinfo_ladder(c) != game_get_gameflag_ladder(game)) {
1149 reply=D2CS_CLIENT_JOINGAMEREPLY_NORMAL_LADDER;
1150 } else if (conn_get_charinfo_expansion(c) != game_get_gameflag_expansion(game)) {
1151 reply=D2CS_CLIENT_JOINGAMEREPLY_CLASSIC_EXPANSION;
1152 } else if (conn_get_charinfo_hardcore(c) != game_get_gameflag_hardcore(game)) {
1153 reply=D2CS_CLIENT_JOINGAMEREPLY_HARDCORE_SOFTCORE;
1154 } else if (conn_get_charinfo_difficulty(c) < game_get_gameflag_difficulty(game)) {
1155 reply=D2CS_CLIENT_JOINGAMEREPLY_NORMAL_NIGHTMARE;
1156 } else if (prefs_allow_gamelimit()) {
1157 if (game_get_maxchar(game) <= game_get_currchar(game)) {
1158 reply=D2CS_CLIENT_JOINGAMEREPLY_GAME_FULL;
1159 } else if (conn_get_charinfo_level(c) > game_get_maxlevel(game)) {
1160 reply=D2CS_CLIENT_JOINGAMEREPLY_LEVEL_LIMIT;
1161 } else if (conn_get_charinfo_level(c) < game_get_minlevel(game)) {
1162 reply=D2CS_CLIENT_JOINGAMEREPLY_LEVEL_LIMIT;
1163 } else if (strcmp(d2cs_game_get_pass(game),gamepass)) {
1164 reply=D2CS_CLIENT_JOINGAMEREPLY_BAD_PASS;
1165 } else {
1166 reply=D2CS_CLIENT_JOINGAMEREPLY_SUCCEED;
1167 }
1168 } else {
1169 if (game_get_currchar(game) >= MAX_CHAR_PER_GAME) {
1170 reply=D2CS_CLIENT_JOINGAMEREPLY_GAME_FULL;
1171 } else {
1172 reply=D2CS_CLIENT_JOINGAMEREPLY_SUCCEED;
1173 }
1174 }
1175 return reply;
1176 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1