viewing paste ra_logincharrefact.diff | Diff

Posted on the
  1. Index: conf/login_athena.conf
  2. ===================================================================
  3. --- conf/login_athena.conf	(revision 17365)
  4. +++ conf/login_athena.conf	(working copy)
  5. @@ -82,8 +82,21 @@
  6.  check_client_version: no
  7.  
  8.  // What version we would allow to connect? (if the options above is enabled..)
  9. -client_version_to_connect: 20
  10. +client_version_to_connect: 30
  11.  
  12. +// Client MD5 hash check
  13. +// If turned on, the login server will check if the client's hash matches
  14. +// the value below, and will not connect tampered clients.
  15. +// Note: see doc\md5_hashcheck.txt for more details.
  16. +client_hash_check: no
  17. +
  18. +// Client MD5 hashes
  19. +// A player can login with a client hash at or below the account group_id.
  20. +// Format: group_id, hash
  21. +client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5
  22. +client_hash: 98, cb1ea78023d337c38e8ba5124e2338ae
  23. +client_hash: 99, any
  24. +
  25.  // Store passwords as MD5 hashes instead of plaintext ?
  26.  // NOTE: Will not work with clients that use <passwordencrypt>
  27.  use_MD5_passwords: no
  28. @@ -145,17 +158,5 @@
  29.  //account.sql.account_db: login
  30.  //account.sql.accreg_db: global_reg_value
  31.  
  32. -// Client MD5 hash check
  33. -// If turned on, the login server will check if the client's hash matches
  34. -// the value below, and will not connect tampered clients.
  35. -// Note: see doc\md5_hashcheck.txt for more details.
  36. -client_hash_check: off
  37. -
  38. -// Client MD5 hashes
  39. -// A player can login with a client hash at or below the account group_id.
  40. -// Format: group_id, hash
  41. -client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5
  42. -client_hash: 99, cb1ea78023d337c38e8ba5124e2338ae
  43. -
  44.  import: conf/inter_athena.conf
  45.  import: conf/import/login_conf.txt
  46. Index: db/packet_db.txt
  47. ===================================================================
  48. --- db/packet_db.txt	(revision 17365)
  49. +++ db/packet_db.txt	(working copy)
  50. @@ -1416,7 +1416,7 @@
  51.  
  52.  //2009-08-18aRagexeRE
  53.  0x07e3,6
  54. -0x07e4,-1,itemlistwindowselected,2:4:8
  55. +0x07e4,-1,itemlistwindowselected,2:4:8:12
  56.  0x07e6,8
  57.  
  58.  //2009-08-25aRagexeRE
  59. @@ -1612,7 +1612,7 @@
  60.  
  61.  //2010-11-24aRagexeRE
  62.  packet_ver: 26
  63. -0x0288,-1,cashshopbuy,2:4:8:10
  64. +0x0288,-1,cashshopbuy,2:4:6:10
  65.  0x0436,19,wanttoconnection,2:6:10:14:18
  66.  0x035f,5,walktoxy,2
  67.  0x0360,6,ticksend,2
  68. @@ -1658,7 +1658,7 @@
  69.  0x083c,19,wanttoconnection,2:6:10:14:18
  70.  0x08aa,7,actionrequest,2:6
  71.  0x02c4,10,useskilltoid,2:4:6
  72. -0x0811,-1,itemlistwindowselected,2:4:8
  73. +0x0811,-1,itemlistwindowselected,2:4:8:12
  74.  0x890,8
  75.  0x08a5,18,bookingregreq,2:4:6
  76.  0x0835,-1,reqopenbuyingstore,2:4:8:9:89
  77. @@ -1689,7 +1689,7 @@
  78.  0x0929,26,partyinvite2,2
  79.  0x0885,7,actionrequest,2:6
  80.  0x0889,10,useskilltoid,2:4:6
  81. -0x0870,-1,itemlistwindowselected,2:4:8
  82. +0x0870,-1,itemlistwindowselected,2:4:8:12
  83.  //0x0926,18,bookingregreq,2:4:6
  84.  0x0815,-1,reqopenbuyingstore,2:4:8:9:89
  85.  0x0817,2,reqclosebuyingstore,0
  86. @@ -1707,13 +1707,13 @@
  87.  0x089c,26,friendslistadd,2
  88.  0x0885,5,hommenu,2:4
  89.  0x0961,36,storagepassword,2:4:20
  90. -0x0288,-1,cashshopbuy,2:4:8:10
  91. +0x0288,-1,cashshopbuy,2:4:6:10
  92.  0x091c,26,partyinvite2,2
  93.  0x094b,19,wanttoconnection,2:6:10:14:18
  94.  0x0369,7,actionrequest,2:6
  95.  0x083c,10,useskilltoid,2:4:6
  96.  0x0439,8,useitem,2:4
  97. -0x0945,-1,itemlistwindowselected,2:4:8
  98. +0x0945,-1,itemlistwindowselected,2:4:8:12
  99.  0x0815,-1,reqopenbuyingstore,2:4:8:9:89
  100.  0x0817,2,reqclosebuyingstore,0
  101.  0x0360,6,reqclickbuyingstore,2
  102. @@ -1769,7 +1769,7 @@
  103.  0x08A8,36,storagepassword,2:4:20
  104.  0x0802,26,partyinvite2,2
  105.  0x022D,19,wanttoconnection,2:6:10:14:18
  106. -0x0281,-1,itemlistwindowselected,2:4:8
  107. +0x0281,-1,itemlistwindowselected,2:4:8:12
  108.  0x035F,6,ticksend,2
  109.  0x0202,5,changedir,2:4
  110.  0x07E4,6,takeitem,2
  111. @@ -1808,7 +1808,7 @@
  112.  packet_ver: 34
  113.  0x014f,6,guildrequestinfo,2
  114.  0x01fd,15,repairitem,2:4:6:7:9:11:13
  115. -//0x0281,-1,itemlistwindowselected,2:4:8
  116. +//0x0281,-1,itemlistwindowselected,2:4:8:12
  117.  0x035f,6,reqclickbuyingstore,2
  118.  0x0363,6,ticksend,2
  119.  0x0365,12,searchstoreinfolistitemclick,2:6:10
  120. @@ -1821,7 +1821,7 @@
  121.  0x084b,19 //fallitem4
  122.  0x085a,90,useskilltoposinfo,2:4:6:8:10
  123.  0x085d,18,bookingregreq,2:4:6
  124. -0x0868,-1,itemlistwindowselected,2:4:8
  125. +0x0868,-1,itemlistwindowselected,2:4:8:12
  126.  0x086d,26,partyinvite2,2
  127.  0x086f,26,friendslistadd,2
  128.  0x0874,8,movefromkafra,2:4
  129. @@ -1891,7 +1891,7 @@
  130.  0x0815,-1,reqopenbuyingstore,2:4:8:9:89
  131.  0x092D,18,bookingregreq,2:4:6
  132.  //0x08AA,8 CZ_JOIN_BATTLE_FIELD
  133. -0x0963,-1,itemlistwindowselected,2:4:8
  134. +0x0963,-1,itemlistwindowselected,2:4:8:12
  135.  0x0943,19,wanttoconnection,2:6:10:14:18
  136.  0x0947,26,partyinvite2,2
  137.  //0x0862,4 CZ_GANGSI_RANK
  138. @@ -1923,7 +1923,7 @@
  139.  0x0874,-1,reqopenbuyingstore,2:4:8:9:89
  140.  0x089B,18,bookingregreq,2:4:6
  141.  //0x0965,8 CZ_JOIN_BATTLE_FIELD
  142. -0x086A,-1,itemlistwindowselected,2:4:8
  143. +0x086A,-1,itemlistwindowselected,2:4:8:12
  144.  0x08A9,19,wanttoconnection,2:6:10:14:18
  145.  0x0950,26,partyinvite2,2
  146.  //0x08AC,4 CZ_GANGSI_RANK
  147. @@ -1955,7 +1955,7 @@
  148.  0x0869,-1,reqopenbuyingstore,2:4:8:9:89
  149.  0x0874,41,bookingregreq,2,4:6
  150.  // 0x088E,8); // CZ_JOIN_BATTLE_FIELD
  151. -0x0958,-1,itemlistwindowselected,2:4:8
  152. +0x0958,-1,itemlistwindowselected,2:4:8:12
  153.  0x0919,19,wanttoconnection,2:6:10:14:18
  154.  0x08A8,26,partyinvite2,2
  155.  // 0x0888,4); // CZ_GANGSI_RANK
  156. @@ -1987,7 +1987,7 @@
  157.  0x0815,-1,reqopenbuyingstore,2:4:8:9:89
  158.  0x0365,41,bookingregreq,2:4:6
  159.  // 0x0363,8 // CZ_JOIN_BATTLE_FIELD
  160. -0x0281,-1,itemlistwindowselected,2:4:8
  161. +0x0281,-1,itemlistwindowselected,2:4:8:12
  162.  0x022D,19,wanttoconnection,2:6:10:14:18
  163.  0x0802,26,partyinvite2,2
  164.  // 0x0436,4 // CZ_GANGSI_RANK
  165. @@ -2019,7 +2019,7 @@
  166.  0x0815,-1,reqopenbuyingstore,2:4:8:9:89
  167.  0x0365,18,bookingregreq,2:4:6
  168.  // 0x0363,8 CZ_JOIN_BATTLE_FIELD
  169. -0x0281,-1,itemlistwindowselected,2:4:8
  170. +0x0281,-1,itemlistwindowselected,2:4:8:12
  171.  0x0919,19,wanttoconnection,2:6:10:14:18
  172.  0x0802,26,partyinvite2,2
  173.  // 0x0436,4 CZ_GANGSI_RANK
  174. Index: src/login/loginlog_sql.c
  175. ===================================================================
  176. --- src/login/loginlog_sql.c	(revision 17365)
  177. +++ src/login/loginlog_sql.c	(working copy)
  178. @@ -1,184 +0,0 @@
  179. -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  180. -// For more information, see LICENCE in the main folder
  181. -
  182. -#include "../common/cbasetypes.h"
  183. -#include "../common/mmo.h"
  184. -#include "../common/socket.h"
  185. -#include "../common/sql.h"
  186. -#include "../common/strlib.h"
  187. -#include <string.h>
  188. -#include <stdlib.h> // exit
  189. -
  190. -// global sql settings (in ipban_sql.c)
  191. -static char   global_db_hostname[32] = "127.0.0.1";
  192. -static uint16 global_db_port = 3306;
  193. -static char   global_db_username[32] = "ragnarok";
  194. -static char   global_db_password[32] = "ragnarok";
  195. -static char   global_db_database[32] = "ragnarok";
  196. -static char   global_codepage[32] = "";
  197. -// local sql settings
  198. -static char   log_db_hostname[32] = "";
  199. -static uint16 log_db_port = 0;
  200. -static char   log_db_username[32] = "";
  201. -static char   log_db_password[32] = "";
  202. -static char   log_db_database[32] = "";
  203. -static char   log_codepage[32] = "";
  204. -static char   log_login_db[256] = "loginlog";
  205. -
  206. -static Sql* sql_handle = NULL;
  207. -static bool enabled = false;
  208. -
  209. -
  210. -// Returns the number of failed login attemps by the ip in the last minutes.
  211. -unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes)
  212. -{
  213. -	unsigned long failures = 0;
  214. -
  215. -	if( !enabled )
  216. -		return 0;
  217. -
  218. -	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE",
  219. -		log_login_db, ip2str(ip,NULL), minutes) )// how many times failed account? in one ip.
  220. -		Sql_ShowDebug(sql_handle);
  221. -
  222. -	if( SQL_SUCCESS == Sql_NextRow(sql_handle) )
  223. -	{
  224. -		char* data;
  225. -		Sql_GetData(sql_handle, 0, &data, NULL);
  226. -		failures = strtoul(data, NULL, 10);
  227. -		Sql_FreeResult(sql_handle);
  228. -	}
  229. -	return failures;
  230. -}
  231. -
  232. -
  233. -/*=============================================
  234. - * Records an event in the login log
  235. - *---------------------------------------------*/
  236. -void login_log(uint32 ip, const char* username, int rcode, const char* message)
  237. -{
  238. -	char esc_username[NAME_LENGTH*2+1];
  239. -	char esc_message[255*2+1];
  240. -	int retcode;
  241. -
  242. -	if( !enabled )
  243. -		return;
  244. -
  245. -	Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH));
  246. -	Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255));
  247. -
  248. -	retcode = Sql_Query(sql_handle,
  249. -		"INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')",
  250. -		log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message);
  251. -
  252. -	if( retcode != SQL_SUCCESS )
  253. -		Sql_ShowDebug(sql_handle);
  254. -}
  255. -
  256. -bool loginlog_init(void)
  257. -{
  258. -	const char* username;
  259. -	const char* password;
  260. -	const char* hostname;
  261. -	uint16      port;
  262. -	const char* database;
  263. -	const char* codepage;
  264. -
  265. -	if( log_db_hostname[0] != '\0' )
  266. -	{// local settings
  267. -		username = log_db_username;
  268. -		password = log_db_password;
  269. -		hostname = log_db_hostname;
  270. -		port     = log_db_port;
  271. -		database = log_db_database;
  272. -		codepage = log_codepage;
  273. -	}
  274. -	else
  275. -	{// global settings
  276. -		username = global_db_username;
  277. -		password = global_db_password;
  278. -		hostname = global_db_hostname;
  279. -		port     = global_db_port;
  280. -		database = global_db_database;
  281. -		codepage = global_codepage;
  282. -	}
  283. -
  284. -	sql_handle = Sql_Malloc();
  285. -
  286. -	if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
  287. -	{
  288. -		Sql_ShowDebug(sql_handle);
  289. -		Sql_Free(sql_handle);
  290. -		exit(EXIT_FAILURE);
  291. -	}
  292. -
  293. -	if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
  294. -		Sql_ShowDebug(sql_handle);
  295. -
  296. -	enabled = true;
  297. -
  298. -	return true;
  299. -}
  300. -
  301. -bool loginlog_final(void)
  302. -{
  303. -	Sql_Free(sql_handle);
  304. -	sql_handle = NULL;
  305. -	return true;
  306. -}
  307. -
  308. -bool loginlog_config_read(const char* key, const char* value)
  309. -{
  310. -	const char* signature;
  311. -
  312. -	signature = "sql.";
  313. -	if( strncmpi(key, signature, strlen(signature)) == 0 )
  314. -	{
  315. -		key += strlen(signature);
  316. -		if( strcmpi(key, "db_hostname") == 0 )
  317. -			safestrncpy(global_db_hostname, value, sizeof(global_db_hostname));
  318. -		else
  319. -		if( strcmpi(key, "db_port") == 0 )
  320. -			global_db_port = (uint16)strtoul(value, NULL, 10);
  321. -		else
  322. -		if( strcmpi(key, "db_username") == 0 )
  323. -			safestrncpy(global_db_username, value, sizeof(global_db_username));
  324. -		else
  325. -		if( strcmpi(key, "db_password") == 0 )
  326. -			safestrncpy(global_db_password, value, sizeof(global_db_password));
  327. -		else
  328. -		if( strcmpi(key, "db_database") == 0 )
  329. -			safestrncpy(global_db_database, value, sizeof(global_db_database));
  330. -		else
  331. -		if( strcmpi(key, "codepage") == 0 )
  332. -			safestrncpy(global_codepage, value, sizeof(global_codepage));
  333. -		else
  334. -			return false;// not found
  335. -		return true;
  336. -	}
  337. -
  338. -	if( strcmpi(key, "log_db_ip") == 0 )
  339. -		safestrncpy(log_db_hostname, value, sizeof(log_db_hostname));
  340. -	else
  341. -	if( strcmpi(key, "log_db_port") == 0 )
  342. -		log_db_port = (uint16)strtoul(value, NULL, 10);
  343. -	else
  344. -	if( strcmpi(key, "log_db_id") == 0 )
  345. -		safestrncpy(log_db_username, value, sizeof(log_db_username));
  346. -	else
  347. -	if( strcmpi(key, "log_db_pw") == 0 )
  348. -		safestrncpy(log_db_password, value, sizeof(log_db_password));
  349. -	else
  350. -	if( strcmpi(key, "log_db_db") == 0 )
  351. -		safestrncpy(log_db_database, value, sizeof(log_db_database));
  352. -	else
  353. -	if( strcmpi(key, "log_codepage") == 0 )
  354. -		safestrncpy(log_codepage, value, sizeof(log_codepage));
  355. -	else
  356. -	if( strcmpi(key, "log_login_db") == 0 )
  357. -		safestrncpy(log_login_db, value, sizeof(log_login_db));
  358. -	else
  359. -		return false;
  360. -
  361. -	return true;
  362. -}
  363. Index: src/login/ipban_sql.c
  364. ===================================================================
  365. --- src/login/ipban_sql.c	(revision 17365)
  366. +++ src/login/ipban_sql.c	(working copy)
  367. @@ -1,258 +0,0 @@
  368. -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  369. -// For more information, see LICENCE in the main folder
  370. -
  371. -#include "../common/cbasetypes.h"
  372. -#include "../common/db.h"
  373. -#include "../common/malloc.h"
  374. -#include "../common/sql.h"
  375. -#include "../common/socket.h"
  376. -#include "../common/strlib.h"
  377. -#include "../common/timer.h"
  378. -#include "login.h"
  379. -#include "ipban.h"
  380. -#include "loginlog.h"
  381. -#include <stdlib.h>
  382. -#include <string.h>
  383. -
  384. -// global sql settings
  385. -static char   global_db_hostname[32] = "127.0.0.1";
  386. -static uint16 global_db_port = 3306;
  387. -static char   global_db_username[32] = "ragnarok";
  388. -static char   global_db_password[32] = "ragnarok";
  389. -static char   global_db_database[32] = "ragnarok";
  390. -static char   global_codepage[32] = "";
  391. -// local sql settings
  392. -static char   ipban_db_hostname[32] = "";
  393. -static uint16 ipban_db_port = 0;
  394. -static char   ipban_db_username[32] = "";
  395. -static char   ipban_db_password[32] = "";
  396. -static char   ipban_db_database[32] = "";
  397. -static char   ipban_codepage[32] = "";
  398. -static char   ipban_table[32] = "ipbanlist";
  399. -
  400. -// globals
  401. -static Sql* sql_handle = NULL;
  402. -static int cleanup_timer_id = INVALID_TIMER;
  403. -static bool ipban_inited = false;
  404. -
  405. -int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data);
  406. -
  407. -
  408. -// initialize
  409. -void ipban_init(void)
  410. -{
  411. -	const char* username;
  412. -	const char* password;
  413. -	const char* hostname;
  414. -	uint16      port;
  415. -	const char* database;
  416. -	const char* codepage;
  417. -
  418. -	ipban_inited = true;
  419. -
  420. -	if( !login_config.ipban )
  421. -		return;// ipban disabled
  422. -
  423. -	if( ipban_db_hostname[0] != '\0' )
  424. -	{// local settings
  425. -		username = ipban_db_username;
  426. -		password = ipban_db_password;
  427. -		hostname = ipban_db_hostname;
  428. -		port     = ipban_db_port;
  429. -		database = ipban_db_database;
  430. -		codepage = ipban_codepage;
  431. -	}
  432. -	else
  433. -	{// global settings
  434. -		username = global_db_username;
  435. -		password = global_db_password;
  436. -		hostname = global_db_hostname;
  437. -		port     = global_db_port;
  438. -		database = global_db_database;
  439. -		codepage = global_codepage;
  440. -	}
  441. -
  442. -	// establish connections
  443. -	sql_handle = Sql_Malloc();
  444. -	if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
  445. -	{
  446. -		Sql_ShowDebug(sql_handle);
  447. -		Sql_Free(sql_handle);
  448. -		exit(EXIT_FAILURE);
  449. -	}
  450. -	if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
  451. -		Sql_ShowDebug(sql_handle);
  452. -
  453. -	if( login_config.ipban_cleanup_interval > 0 )
  454. -	{ // set up periodic cleanup of connection history and active bans
  455. -		add_timer_func_list(ipban_cleanup, "ipban_cleanup");
  456. -		cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000);
  457. -	} else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups
  458. -		ipban_cleanup(0,0,0,0);
  459. -}
  460. -
  461. -// finalize
  462. -void ipban_final(void)
  463. -{
  464. -	if( !login_config.ipban )
  465. -		return;// ipban disabled
  466. -
  467. -	if( login_config.ipban_cleanup_interval > 0 )
  468. -		// release data
  469. -		delete_timer(cleanup_timer_id, ipban_cleanup);
  470. -	
  471. -	ipban_cleanup(0,0,0,0); // always clean up on login-server stop
  472. -
  473. -	// close connections
  474. -	Sql_Free(sql_handle);
  475. -	sql_handle = NULL;
  476. -}
  477. -
  478. -// load configuration options
  479. -bool ipban_config_read(const char* key, const char* value)
  480. -{
  481. -	const char* signature;
  482. -
  483. -	if( ipban_inited )
  484. -		return false;// settings can only be changed before init
  485. -
  486. -	signature = "sql.";
  487. -	if( strncmpi(key, signature, strlen(signature)) == 0 )
  488. -	{
  489. -		key += strlen(signature);
  490. -		if( strcmpi(key, "db_hostname") == 0 )
  491. -			safestrncpy(global_db_hostname, value, sizeof(global_db_hostname));
  492. -		else
  493. -		if( strcmpi(key, "db_port") == 0 )
  494. -			global_db_port = (uint16)strtoul(value, NULL, 10);
  495. -		else
  496. -		if( strcmpi(key, "db_username") == 0 )
  497. -			safestrncpy(global_db_username, value, sizeof(global_db_username));
  498. -		else
  499. -		if( strcmpi(key, "db_password") == 0 )
  500. -			safestrncpy(global_db_password, value, sizeof(global_db_password));
  501. -		else
  502. -		if( strcmpi(key, "db_database") == 0 )
  503. -			safestrncpy(global_db_database, value, sizeof(global_db_database));
  504. -		else
  505. -		if( strcmpi(key, "codepage") == 0 )
  506. -			safestrncpy(global_codepage, value, sizeof(global_codepage));
  507. -		else
  508. -			return false;// not found
  509. -		return true;
  510. -	}
  511. -
  512. -	signature = "ipban.sql.";
  513. -	if( strncmpi(key, signature, strlen(signature)) == 0 )
  514. -	{
  515. -		key += strlen(signature);
  516. -		if( strcmpi(key, "db_hostname") == 0 )
  517. -			safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname));
  518. -		else
  519. -		if( strcmpi(key, "db_port") == 0 )
  520. -			ipban_db_port = (uint16)strtoul(value, NULL, 10);
  521. -		else
  522. -		if( strcmpi(key, "db_username") == 0 )
  523. -			safestrncpy(ipban_db_username, value, sizeof(ipban_db_username));
  524. -		else
  525. -		if( strcmpi(key, "db_password") == 0 )
  526. -			safestrncpy(ipban_db_password, value, sizeof(ipban_db_password));
  527. -		else
  528. -		if( strcmpi(key, "db_database") == 0 )
  529. -			safestrncpy(ipban_db_database, value, sizeof(ipban_db_database));
  530. -		else
  531. -		if( strcmpi(key, "codepage") == 0 )
  532. -			safestrncpy(ipban_codepage, value, sizeof(ipban_codepage));
  533. -		else
  534. -		if( strcmpi(key, "ipban_table") == 0 )
  535. -			safestrncpy(ipban_table, value, sizeof(ipban_table));
  536. -		else
  537. -			return false;// not found
  538. -		return true;
  539. -	}
  540. -
  541. -	signature = "ipban.";
  542. -	if( strncmpi(key, signature, strlen(signature)) == 0 )
  543. -	{
  544. -		key += strlen(signature);
  545. -		if( strcmpi(key, "enable") == 0 )
  546. -			login_config.ipban = (bool)config_switch(value);
  547. -		else
  548. -		if( strcmpi(key, "dynamic_pass_failure_ban") == 0 )
  549. -			login_config.dynamic_pass_failure_ban = (bool)config_switch(value);
  550. -		else
  551. -		if( strcmpi(key, "dynamic_pass_failure_ban_interval") == 0 )
  552. -			login_config.dynamic_pass_failure_ban_interval = atoi(value);
  553. -		else
  554. -		if( strcmpi(key, "dynamic_pass_failure_ban_limit") == 0 )
  555. -			login_config.dynamic_pass_failure_ban_limit = atoi(value);
  556. -		else
  557. -		if( strcmpi(key, "dynamic_pass_failure_ban_duration") == 0 )
  558. -			login_config.dynamic_pass_failure_ban_duration = atoi(value);
  559. -		else
  560. -			return false;// not found
  561. -		return true;
  562. -	}
  563. -
  564. -	return false;// not found
  565. -}
  566. -
  567. -// check ip against active bans list
  568. -bool ipban_check(uint32 ip)
  569. -{
  570. -	uint8* p = (uint8*)&ip;
  571. -	char* data = NULL;
  572. -	int matches;
  573. -
  574. -	if( !login_config.ipban )
  575. -		return false;// ipban disabled
  576. -
  577. -	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')",
  578. -		ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]) )
  579. -	{
  580. -		Sql_ShowDebug(sql_handle);
  581. -		// close connection because we can't verify their connectivity.
  582. -		return true;
  583. -	}
  584. -
  585. -	if( SQL_ERROR == Sql_NextRow(sql_handle) )
  586. -		return true;// Shouldn't happen, but just in case...
  587. -
  588. -	Sql_GetData(sql_handle, 0, &data, NULL);
  589. -	matches = atoi(data);
  590. -	Sql_FreeResult(sql_handle);
  591. -
  592. -	return( matches > 0 );
  593. -}
  594. -
  595. -// log failed attempt
  596. -void ipban_log(uint32 ip)
  597. -{
  598. -	unsigned long failures;
  599. -
  600. -	if( !login_config.ipban )
  601. -		return;// ipban disabled
  602. -
  603. -	failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip.
  604. -
  605. -	// if over the limit, add a temporary ban entry
  606. -	if( failures >= login_config.dynamic_pass_failure_ban_limit )
  607. -	{
  608. -		uint8* p = (uint8*)&ip;
  609. -		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() +  INTERVAL %d MINUTE ,'Password error ban')",
  610. -			ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration) )
  611. -			Sql_ShowDebug(sql_handle);
  612. -	}
  613. -}
  614. -
  615. -// remove expired bans
  616. -int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data)
  617. -{
  618. -	if( !login_config.ipban )
  619. -		return 0;// ipban disabled
  620. -
  621. -	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()") )
  622. -		Sql_ShowDebug(sql_handle);
  623. -
  624. -	return 0;
  625. -}
  626. Index: src/login/login.c
  627. ===================================================================
  628. --- src/login/login.c	(revision 17365)
  629. +++ src/login/login.c	(working copy)
  630. @@ -11,12 +11,14 @@
  631.  #include "../common/strlib.h"
  632.  #include "../common/timer.h"
  633.  #include "../common/msg_conf.h"
  634. -#include "../common/cli.h"
  635. -#include "../common/ers.h"
  636. +#include "../common/utils.h"
  637.  #include "account.h"
  638.  #include "ipban.h"
  639.  #include "login.h"
  640.  #include "loginlog.h"
  641. +#include "loginclif.h"
  642. +#include "loginchrif.h"
  643. +#include "logincnslif.h"
  644.  
  645.  #include <stdio.h>
  646.  #include <stdlib.h>
  647. @@ -24,11 +26,6 @@
  648.  
  649.  #define LOGIN_MAX_MSG 30
  650.  static char* msg_table[LOGIN_MAX_MSG]; // Login Server messages_conf
  651. -struct Login_Config login_config;
  652. -
  653. -int login_fd; // login server socket
  654. -struct mmo_char_server server[MAX_SERVERS]; // char server data
  655. -
  656.  // Account engines available
  657.  static struct{
  658.  	AccountDB* (*constructor)(void);
  659. @@ -53,60 +50,25 @@
  660.  	// end of structure
  661.  	{NULL, NULL}
  662.  };
  663. -// account database
  664. -AccountDB* accounts = NULL;
  665. -
  666. -//Account registration flood protection [Kevin]
  667. -int allowed_regs = 1;
  668. -int time_allowed = 10; //in seconds
  669. -
  670. +AccountDB* accounts = NULL; // account database«
  671.  // Advanced subnet check [LuzZza]
  672.  struct s_subnet {
  673.  	uint32 mask;
  674.  	uint32 char_ip;
  675.  	uint32 map_ip;
  676.  } subnet[16];
  677. -
  678.  int subnet_count = 0;
  679.  
  680. -int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip);
  681. +int login_fd; // login server socket
  682.  
  683. -//-----------------------------------------------------
  684. -// Auth database
  685. -//-----------------------------------------------------
  686. -#define AUTH_TIMEOUT 30000
  687. +AccountDB* login_get_accounts_db(void){
  688. +	return accounts;
  689. +}
  690.  
  691. -struct auth_node {
  692. -
  693. -	int account_id;
  694. -	uint32 login_id1;
  695. -	uint32 login_id2;
  696. -	uint32 ip;
  697. -	char sex;
  698. -	uint32 version;
  699. -	uint8 clienttype;
  700. -};
  701. -
  702. -static DBMap* auth_db; // int account_id -> struct auth_node*
  703. -
  704. -
  705. -//-----------------------------------------------------
  706. -// Online User Database [Wizputer]
  707. -//-----------------------------------------------------
  708. -struct online_login_data {
  709. -
  710. -	int account_id;
  711. -	int waiting_disconnect;
  712. -	int char_server;
  713. -};
  714. -
  715. -static DBMap* online_db; // int account_id -> struct online_login_data*
  716. -static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data);
  717. -
  718.  /**
  719.   * @see DBCreateData
  720.   */
  721. -static DBData create_online_user(DBKey key, va_list args)
  722. +DBData create_online_user(DBKey key, va_list args)
  723.  {
  724.  	struct online_login_data* p;
  725.  	CREATE(p, struct online_login_data, 1);
  726. @@ -141,7 +103,7 @@
  727.  	idb_remove(online_db, account_id);
  728.  }
  729.  
  730. -static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data)
  731. +int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data)
  732.  {
  733.  	struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id);
  734.  	if( p != NULL && p->waiting_disconnect == tid && p->account_id == id )
  735. @@ -154,9 +116,9 @@
  736.  }
  737.  
  738.  /**
  739. - * @see DBApply
  740. + * Mark a char offline
  741.   */
  742. -static int online_db_setoffline(DBKey key, DBData *data, va_list ap)
  743. +int online_db_setoffline(DBKey key, DBData *data, va_list ap)
  744.  {
  745.  	struct online_login_data* p = db_data2ptr(data);
  746.  	int server = va_arg(ap, int);
  747. @@ -192,766 +154,7 @@
  748.  }
  749.  
  750.  
  751. -//--------------------------------------------------------------------
  752. -// Packet send to all char-servers, except one (wos: without our self)
  753. -//--------------------------------------------------------------------
  754. -int charif_sendallwos(int sfd, uint8* buf, size_t len)
  755. -{
  756. -	int i, c;
  757.  
  758. -	for( i = 0, c = 0; i < ARRAYLENGTH(server); ++i )
  759. -	{
  760. -		int fd = server[i].fd;
  761. -		if( session_isValid(fd) && fd != sfd )
  762. -		{
  763. -			WFIFOHEAD(fd,len);
  764. -			memcpy(WFIFOP(fd,0), buf, len);
  765. -			WFIFOSET(fd,len);
  766. -			++c;
  767. -		}
  768. -	}
  769. -
  770. -	return c;
  771. -}
  772. -
  773. -
  774. -/// Initializes a server structure.
  775. -void chrif_server_init(int id)
  776. -{
  777. -	memset(&server[id], 0, sizeof(server[id]));
  778. -	server[id].fd = -1;
  779. -}
  780. -
  781. -
  782. -/// Destroys a server structure.
  783. -void chrif_server_destroy(int id)
  784. -{
  785. -	if( server[id].fd != -1 )
  786. -	{
  787. -		do_close(server[id].fd);
  788. -		server[id].fd = -1;
  789. -	}
  790. -}
  791. -
  792. -
  793. -/// Resets all the data related to a server.
  794. -void chrif_server_reset(int id)
  795. -{
  796. -	online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline.
  797. -	chrif_server_destroy(id);
  798. -	chrif_server_init(id);
  799. -}
  800. -
  801. -
  802. -/// Called when the connection to Char Server is disconnected.
  803. -void chrif_on_disconnect(int id)
  804. -{
  805. -	ShowStatus("Char-server '%s' has disconnected.\n", server[id].name);
  806. -	chrif_server_reset(id);
  807. -}
  808. -
  809. -
  810. -//-----------------------------------------------------
  811. -// periodic ip address synchronization
  812. -//-----------------------------------------------------
  813. -static int sync_ip_addresses(int tid, unsigned int tick, int id, intptr_t data)
  814. -{
  815. -	uint8 buf[2];
  816. -	ShowInfo("IP Sync in progress...\n");
  817. -	WBUFW(buf,0) = 0x2735;
  818. -	charif_sendallwos(-1, buf, 2);
  819. -	return 0;
  820. -}
  821. -
  822. -
  823. -//-----------------------------------------------------
  824. -// encrypted/unencrypted password check (from eApp)
  825. -//-----------------------------------------------------
  826. -bool check_encrypted(const char* str1, const char* str2, const char* passwd)
  827. -{
  828. -	char tmpstr[64+1], md5str[32+1];
  829. -
  830. -	safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
  831. -	MD5_String(tmpstr, md5str);
  832. -
  833. -	return (0==strcmp(passwd, md5str));
  834. -}
  835. -
  836. -bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass)
  837. -{
  838. -	if(passwdenc == 0)
  839. -	{
  840. -		return (0==strcmp(passwd, refpass));
  841. -	}
  842. -	else
  843. -	{
  844. -		// password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
  845. -		// password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
  846. -
  847. -		return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) ||
  848. -		       ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd));
  849. -	}
  850. -}
  851. -
  852. -
  853. -//-----------------------------------------------------
  854. -// custom timestamp formatting (from eApp)
  855. -//-----------------------------------------------------
  856. -const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
  857. -{
  858. -	size_t len = strftime(str, size, format, localtime(&timestamp));
  859. -	memset(str + len, '\0', size - len);
  860. -	return str;
  861. -}
  862. -
  863. -
  864. -//--------------------------------------------
  865. -// Test to know if an IP come from LAN or WAN.
  866. -//--------------------------------------------
  867. -int lan_subnetcheck(uint32 ip)
  868. -{
  869. -	int i;
  870. -	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  871. -	return ( i < subnet_count ) ? subnet[i].char_ip : 0;
  872. -}
  873. -
  874. -//----------------------------------
  875. -// Reading Lan Support configuration
  876. -//----------------------------------
  877. -int login_lan_config_read(const char *lancfgName)
  878. -{
  879. -	FILE *fp;
  880. -	int line_num = 0;
  881. -	char line[1024], w1[64], w2[64], w3[64], w4[64];
  882. -
  883. -	if((fp = fopen(lancfgName, "r")) == NULL) {
  884. -		ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
  885. -		return 1;
  886. -	}
  887. -
  888. -	while(fgets(line, sizeof(line), fp))
  889. -	{
  890. -		line_num++;
  891. -		if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
  892. -			continue;
  893. -
  894. -		if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4)
  895. -		{
  896. -			ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
  897. -			continue;
  898. -		}
  899. -
  900. -		if( strcmpi(w1, "subnet") == 0 )
  901. -		{
  902. -			subnet[subnet_count].mask = str2ip(w2);
  903. -			subnet[subnet_count].char_ip = str2ip(w3);
  904. -			subnet[subnet_count].map_ip = str2ip(w4);
  905. -
  906. -			if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
  907. -			{
  908. -				ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
  909. -				continue;
  910. -			}
  911. -
  912. -			subnet_count++;
  913. -		}
  914. -	}
  915. -
  916. -	if( subnet_count > 1 ) /* only useful if there is more than 1 available */
  917. -		ShowStatus("Read information about %d subnetworks.\n", subnet_count);
  918. -
  919. -	fclose(fp);
  920. -	return 0;
  921. -}
  922. -
  923. -//-----------------------
  924. -// Console Command Parser [Wizputer]
  925. -//-----------------------
  926. -int parse_console(const char* buf){
  927. -	char type[64];
  928. -	char command[64];
  929. -	int n=0;
  930. -
  931. -	if( ( n = sscanf(buf, "%127[^:]:%255[^\n\r]", type, command) ) < 2 ){
  932. -		if((n = sscanf(buf, "%63[^\n]", type))<1) return -1; //nothing to do no arg
  933. -	}
  934. -	if( n != 2 ){ //end string
  935. -		ShowNotice("Type: '%s'\n",type);
  936. -		command[0] = '\0';
  937. -	}
  938. -	else
  939. -		ShowNotice("Type of command: '%s' || Command: '%s'\n",type,command);
  940. -
  941. -	if( n == 2 ){
  942. -		if(strcmpi("server", type) == 0 ){
  943. -			if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 ){
  944. -				runflag = 0;
  945. -			}
  946. -			else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 )
  947. -				ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n");
  948. -		}
  949. -		if( strcmpi("create",type) == 0 )
  950. -		{
  951. -			char username[NAME_LENGTH], password[NAME_LENGTH], md5password[32+1], sex; //23+1 plaintext 32+1 md5
  952. -			bool md5 = 0;
  953. -			if( sscanf(command, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ){
  954. -				ShowWarning("Console: Invalid parameters for '%s'. Usage: %s <username> <password> <sex:F/M>\n", type, type);
  955. -				return 0;
  956. -			}
  957. -			if( login_config.use_md5_passwds ){
  958. -				MD5_String(password,md5password);
  959. -				md5 = 1;
  960. -			}
  961. -			if( mmo_auth_new(username,(md5?md5password:password), TOUPPER(sex), "0.0.0.0") != -1 ){
  962. -				ShowError("Console: Account creation failed.\n");
  963. -				return 0;
  964. -			}
  965. -			ShowStatus("Console: Account '%s' created successfully.\n", username);
  966. -		}
  967. -	}
  968. -	else if( strcmpi("ers_report", type) == 0 ){
  969. -		ers_report();
  970. -	}
  971. -	else if( strcmpi("help", type) == 0 ){
  972. -		ShowInfo("Available commands:\n");
  973. -		ShowInfo("\t server:shutdown => Stops the server.\n");
  974. -		ShowInfo("\t server:alive => Checks if the server is running.\n");
  975. -		ShowInfo("\t ers_report => Displays database usage.\n");
  976. -		ShowInfo("\t create:<username> <password> <sex:M|F> => Creates a new account.\n");
  977. -	}
  978. -	else{ // commands with parameters
  979. -
  980. -
  981. -
  982. -	}
  983. -
  984. -	return 0;
  985. -}
  986. -
  987. -
  988. -//--------------------------------
  989. -// Packet parsing for char-servers
  990. -//--------------------------------
  991. -int parse_fromchar(int fd){
  992. -	int j, id;
  993. -	uint32 ipl;
  994. -	char ip[16];
  995. -
  996. -	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  997. -	if( id == ARRAYLENGTH(server) ){// not a char server
  998. -		ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd);
  999. -		set_eof(fd);
  1000. -		do_close(fd);
  1001. -		return 0;
  1002. -	}
  1003. -
  1004. -	if( session[fd]->flag.eof ){
  1005. -		do_close(fd);
  1006. -		server[id].fd = -1;
  1007. -		chrif_on_disconnect(id);
  1008. -		return 0;
  1009. -	}
  1010. -
  1011. -	ipl = server[id].ip;
  1012. -	ip2str(ipl, ip);
  1013. -
  1014. -	while( RFIFOREST(fd) >= 2 ){
  1015. -		uint16 command = RFIFOW(fd,0);
  1016. -
  1017. -		switch( command ){
  1018. -
  1019. -		case 0x2712: // request from char-server to authenticate an account
  1020. -			if( RFIFOREST(fd) < 23 )
  1021. -				return 0;
  1022. -			else{
  1023. -				struct auth_node* node;
  1024. -				int account_id = RFIFOL(fd,2);
  1025. -				uint32 login_id1 = RFIFOL(fd,6);
  1026. -				uint32 login_id2 = RFIFOL(fd,10);
  1027. -				uint8 sex = RFIFOB(fd,14);
  1028. -				//uint32 ip_ = ntohl(RFIFOL(fd,15));
  1029. -				int request_id = RFIFOL(fd,19);
  1030. -				RFIFOSKIP(fd,23);
  1031. -
  1032. -				node = (struct auth_node*)idb_get(auth_db, account_id);
  1033. -				if( runflag == LOGINSERVER_ST_RUNNING &&
  1034. -					node != NULL &&
  1035. -					node->account_id == account_id &&
  1036. -					node->login_id1  == login_id1 &&
  1037. -					node->login_id2  == login_id2 &&
  1038. -					node->sex        == sex_num2str(sex) /*&&
  1039. -					node->ip         == ip_*/ ){// found
  1040. -					//ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip);
  1041. -
  1042. -					// send ack
  1043. -					WFIFOHEAD(fd,25);
  1044. -					WFIFOW(fd,0) = 0x2713;
  1045. -					WFIFOL(fd,2) = account_id;
  1046. -					WFIFOL(fd,6) = login_id1;
  1047. -					WFIFOL(fd,10) = login_id2;
  1048. -					WFIFOB(fd,14) = sex;
  1049. -					WFIFOB(fd,15) = 0;// ok
  1050. -					WFIFOL(fd,16) = request_id;
  1051. -					WFIFOL(fd,20) = node->version;
  1052. -					WFIFOB(fd,24) = node->clienttype;
  1053. -					WFIFOSET(fd,25);
  1054. -
  1055. -					// each auth entry can only be used once
  1056. -					idb_remove(auth_db, account_id);
  1057. -				}else{// authentication not found
  1058. -					ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip);
  1059. -					WFIFOHEAD(fd,25);
  1060. -					WFIFOW(fd,0) = 0x2713;
  1061. -					WFIFOL(fd,2) = account_id;
  1062. -					WFIFOL(fd,6) = login_id1;
  1063. -					WFIFOL(fd,10) = login_id2;
  1064. -					WFIFOB(fd,14) = sex;
  1065. -					WFIFOB(fd,15) = 1;// auth failed
  1066. -					WFIFOL(fd,16) = request_id;
  1067. -					WFIFOL(fd,20) = 0;
  1068. -					WFIFOB(fd,24) = 0;
  1069. -					WFIFOSET(fd,25);
  1070. -				}
  1071. -			}
  1072. -		break;
  1073. -
  1074. -		case 0x2714:
  1075. -			if( RFIFOREST(fd) < 6 )
  1076. -				return 0;
  1077. -			else{
  1078. -				int users = RFIFOL(fd,2);
  1079. -				RFIFOSKIP(fd,6);
  1080. -
  1081. -				// how many users on world? (update)
  1082. -				if( server[id].users != users ){
  1083. -					ShowStatus("set users %s : %d\n", server[id].name, users);
  1084. -
  1085. -					server[id].users = users;
  1086. -				}
  1087. -			}
  1088. -		break;
  1089. -
  1090. -		case 0x2715: // request from char server to change e-email from default "[email protected]"
  1091. -			if (RFIFOREST(fd) < 46)
  1092. -				return 0;
  1093. -			else{
  1094. -				struct mmo_account acc;
  1095. -				char email[40];
  1096. -
  1097. -				int account_id = RFIFOL(fd,2);
  1098. -				safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email);
  1099. -				RFIFOSKIP(fd,46);
  1100. -
  1101. -				if( e_mail_check(email) == 0 )
  1102. -					ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip);
  1103. -				else if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "[email protected]") == 0 || acc.email[0] == '\0' )
  1104. -					ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  1105. -				else{
  1106. -					memcpy(acc.email, email, 40);
  1107. -					ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip);
  1108. -					// Save
  1109. -					accounts->save(accounts, &acc);
  1110. -				}
  1111. -			}
  1112. -		break;
  1113. -
  1114. -		case 0x2716: // request account data
  1115. -			if( RFIFOREST(fd) < 6 )
  1116. -				return 0;
  1117. -			else{
  1118. -				struct mmo_account acc;
  1119. -				time_t expiration_time = 0;
  1120. -				char email[40] = "";
  1121. -				uint8 char_slots = 0;
  1122. -				int group_id = 0;
  1123. -				char birthdate[10+1] = "";
  1124. -				char pincode[PINCODE_LENGTH+1];
  1125. -				int account_id = RFIFOL(fd,2);
  1126. -
  1127. -				memset(pincode,0,PINCODE_LENGTH+1);
  1128. -
  1129. -				RFIFOSKIP(fd,6);
  1130. -
  1131. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1132. -					ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip);
  1133. -				else{
  1134. -					safestrncpy(email, acc.email, sizeof(email));
  1135. -					expiration_time = acc.expiration_time;
  1136. -					group_id = acc.group_id;
  1137. -					char_slots = acc.char_slots;
  1138. -					safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
  1139. -					safestrncpy(pincode, acc.pincode, sizeof(pincode));
  1140. -				}
  1141. -
  1142. -				WFIFOHEAD(fd,72);
  1143. -				WFIFOW(fd,0) = 0x2717;
  1144. -				WFIFOL(fd,2) = account_id;
  1145. -				safestrncpy((char*)WFIFOP(fd,6), email, 40);
  1146. -				WFIFOL(fd,46) = (uint32)expiration_time;
  1147. -				WFIFOB(fd,50) = (unsigned char)group_id;
  1148. -				WFIFOB(fd,51) = char_slots;
  1149. -				safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
  1150. -				safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
  1151. -				WFIFOL(fd,68) = (uint32)acc.pincode_change;
  1152. -				WFIFOSET(fd,72);
  1153. -			}
  1154. -		break;
  1155. -
  1156. -		case 0x2719: // ping request from charserver
  1157. -			RFIFOSKIP(fd,2);
  1158. -
  1159. -			WFIFOHEAD(fd,2);
  1160. -			WFIFOW(fd,0) = 0x2718;
  1161. -			WFIFOSET(fd,2);
  1162. -		break;
  1163. -
  1164. -		// Map server send information to change an email of an account via char-server
  1165. -		case 0x2722:	// 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  1166. -			if (RFIFOREST(fd) < 86)
  1167. -				return 0;
  1168. -			else{
  1169. -				struct mmo_account acc;
  1170. -				char actual_email[40];
  1171. -				char new_email[40];
  1172. -
  1173. -				int account_id = RFIFOL(fd,2);
  1174. -				safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40);
  1175. -				safestrncpy(new_email, (char*)RFIFOP(fd,46), 40);
  1176. -				RFIFOSKIP(fd, 86);
  1177. -
  1178. -				if( e_mail_check(actual_email) == 0 )
  1179. -					ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip);
  1180. -				else if( e_mail_check(new_email) == 0 )
  1181. -					ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip);
  1182. -				else if( strcmpi(new_email, "[email protected]") == 0 )
  1183. -					ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip);
  1184. -				else if( !accounts->load_num(accounts, &acc, account_id) )
  1185. -					ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  1186. -				else if( strcmpi(acc.email, actual_email) != 0 )
  1187. -					ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip);
  1188. -				else{
  1189. -					safestrncpy(acc.email, new_email, 40);
  1190. -					ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip);
  1191. -					// Save
  1192. -					accounts->save(accounts, &acc);
  1193. -				}
  1194. -			}
  1195. -		break;
  1196. -
  1197. -		case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server)
  1198. -			if (RFIFOREST(fd) < 10)
  1199. -				return 0;
  1200. -			else{
  1201. -				struct mmo_account acc;
  1202. -
  1203. -				int account_id = RFIFOL(fd,2);
  1204. -				unsigned int state = RFIFOL(fd,6);
  1205. -				RFIFOSKIP(fd,10);
  1206. -
  1207. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1208. -					ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip);
  1209. -				else if( acc.state == state )
  1210. -					ShowNotice("Char-server '%s':  Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip);
  1211. -				else{
  1212. -					ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip);
  1213. -
  1214. -					acc.state = state;
  1215. -					// Save
  1216. -					accounts->save(accounts, &acc);
  1217. -
  1218. -					// notify other servers
  1219. -					if (state != 0){
  1220. -						uint8 buf[11];
  1221. -						WBUFW(buf,0) = 0x2731;
  1222. -						WBUFL(buf,2) = account_id;
  1223. -						WBUFB(buf,6) = 0; // 0: change of state, 1: ban
  1224. -						WBUFL(buf,7) = state; // status or final date of a banishment
  1225. -						charif_sendallwos(-1, buf, 11);
  1226. -					}
  1227. -				}
  1228. -			}
  1229. -		break;
  1230. -
  1231. -		case 0x2725: // Receiving of map-server via char-server a ban request
  1232. -			if (RFIFOREST(fd) < 18)
  1233. -				return 0;
  1234. -			else{
  1235. -				struct mmo_account acc;
  1236. -
  1237. -				int account_id = RFIFOL(fd,2);
  1238. -				int year = (short)RFIFOW(fd,6);
  1239. -				int month = (short)RFIFOW(fd,8);
  1240. -				int mday = (short)RFIFOW(fd,10);
  1241. -				int hour = (short)RFIFOW(fd,12);
  1242. -				int min = (short)RFIFOW(fd,14);
  1243. -				int sec = (short)RFIFOW(fd,16);
  1244. -				RFIFOSKIP(fd,18);
  1245. -
  1246. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1247. -					ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  1248. -				else{
  1249. -					time_t timestamp;
  1250. -					struct tm *tmtime;
  1251. -					if (acc.unban_time == 0 || acc.unban_time < time(NULL))
  1252. -						timestamp = time(NULL); // new ban
  1253. -					else
  1254. -						timestamp = acc.unban_time; // add to existing ban
  1255. -					tmtime = localtime(&timestamp);
  1256. -					tmtime->tm_year = tmtime->tm_year + year;
  1257. -					tmtime->tm_mon  = tmtime->tm_mon + month;
  1258. -					tmtime->tm_mday = tmtime->tm_mday + mday;
  1259. -					tmtime->tm_hour = tmtime->tm_hour + hour;
  1260. -					tmtime->tm_min  = tmtime->tm_min + min;
  1261. -					tmtime->tm_sec  = tmtime->tm_sec + sec;
  1262. -					timestamp = mktime(tmtime);
  1263. -					if (timestamp == -1)
  1264. -						ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip);
  1265. -					else if( timestamp <= time(NULL) || timestamp == 0 )
  1266. -						ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip);
  1267. -					else{
  1268. -						uint8 buf[11];
  1269. -						char tmpstr[24];
  1270. -						timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format);
  1271. -						ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip);
  1272. -
  1273. -						acc.unban_time = timestamp;
  1274. -
  1275. -						// Save
  1276. -						accounts->save(accounts, &acc);
  1277. -
  1278. -						WBUFW(buf,0) = 0x2731;
  1279. -						WBUFL(buf,2) = account_id;
  1280. -						WBUFB(buf,6) = 1; // 0: change of status, 1: ban
  1281. -						WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment
  1282. -						charif_sendallwos(-1, buf, 11);
  1283. -					}
  1284. -				}
  1285. -			}
  1286. -		break;
  1287. -
  1288. -		case 0x2727: // Change of sex (sex is reversed)
  1289. -			if( RFIFOREST(fd) < 6 )
  1290. -				return 0;
  1291. -			else{
  1292. -				struct mmo_account acc;
  1293. -
  1294. -				int account_id = RFIFOL(fd,2);
  1295. -				RFIFOSKIP(fd,6);
  1296. -
  1297. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1298. -					ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  1299. -				else if( acc.sex == 'S' )
  1300. -					ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  1301. -				else{
  1302. -					unsigned char buf[7];
  1303. -					char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender
  1304. -
  1305. -					ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip);
  1306. -
  1307. -					acc.sex = sex;
  1308. -					// Save
  1309. -					accounts->save(accounts, &acc);
  1310. -
  1311. -					// announce to other servers
  1312. -					WBUFW(buf,0) = 0x2723;
  1313. -					WBUFL(buf,2) = account_id;
  1314. -					WBUFB(buf,6) = sex_str2num(sex);
  1315. -					charif_sendallwos(-1, buf, 7);
  1316. -				}
  1317. -			}
  1318. -		break;
  1319. -
  1320. -		case 0x2728:	// We receive account_reg2 from a char-server, and we send them to other map-servers.
  1321. -			if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) )
  1322. -				return 0;
  1323. -			else{
  1324. -				struct mmo_account acc;
  1325. -
  1326. -				int account_id = RFIFOL(fd,4);
  1327. -
  1328. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1329. -					ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  1330. -				else{
  1331. -					int len;
  1332. -					int p;
  1333. -					ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  1334. -					for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ){
  1335. -						sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len);
  1336. -						acc.account_reg2[j].str[len]='\0';
  1337. -						p +=len+1; //+1 to skip the '\0' between strings.
  1338. -						sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len);
  1339. -						acc.account_reg2[j].value[len]='\0';
  1340. -						p +=len+1;
  1341. -						remove_control_chars(acc.account_reg2[j].str);
  1342. -						remove_control_chars(acc.account_reg2[j].value);
  1343. -					}
  1344. -					acc.account_reg2_num = j;
  1345. -
  1346. -					// Save
  1347. -					accounts->save(accounts, &acc);
  1348. -
  1349. -					// Sending information towards the other char-servers.
  1350. -					RFIFOW(fd,0) = 0x2729;// reusing read buffer
  1351. -					charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2));
  1352. -				}
  1353. -				RFIFOSKIP(fd,RFIFOW(fd,2));
  1354. -			}
  1355. -		break;
  1356. -
  1357. -		case 0x272a:	// Receiving of map-server via char-server an unban request
  1358. -			if( RFIFOREST(fd) < 6 )
  1359. -				return 0;
  1360. -			else{
  1361. -				struct mmo_account acc;
  1362. -
  1363. -				int account_id = RFIFOL(fd,2);
  1364. -				RFIFOSKIP(fd,6);
  1365. -
  1366. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1367. -					ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  1368. -				else if( acc.unban_time == 0 )
  1369. -					ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip);
  1370. -				else{
  1371. -					ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  1372. -					acc.unban_time = 0;
  1373. -					accounts->save(accounts, &acc);
  1374. -				}
  1375. -			}
  1376. -		break;
  1377. -
  1378. -		case 0x272b:    // Set account_id to online [Wizputer]
  1379. -			if( RFIFOREST(fd) < 6 )
  1380. -				return 0;
  1381. -			add_online_user(id, RFIFOL(fd,2));
  1382. -			RFIFOSKIP(fd,6);
  1383. -		break;
  1384. -
  1385. -		case 0x272c:   // Set account_id to offline [Wizputer]
  1386. -			if( RFIFOREST(fd) < 6 )
  1387. -				return 0;
  1388. -			remove_online_user(RFIFOL(fd,2));
  1389. -			RFIFOSKIP(fd,6);
  1390. -		break;
  1391. -
  1392. -		case 0x272d:	// Receive list of all online accounts. [Skotlex]
  1393. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1394. -				return 0;
  1395. -			else{
  1396. -				struct online_login_data *p;
  1397. -				int aid;
  1398. -				uint32 i, users;
  1399. -				online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first
  1400. -				users = RFIFOW(fd,4);
  1401. -				for (i = 0; i < users; i++) {
  1402. -					aid = RFIFOL(fd,6+i*4);
  1403. -					p = idb_ensure(online_db, aid, create_online_user);
  1404. -					p->char_server = id;
  1405. -					if (p->waiting_disconnect != INVALID_TIMER){
  1406. -						delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
  1407. -						p->waiting_disconnect = INVALID_TIMER;
  1408. -					}
  1409. -				}
  1410. -
  1411. -				RFIFOSKIP(fd,RFIFOW(fd,2));
  1412. -			}
  1413. -		break;
  1414. -
  1415. -		case 0x272e: //Request account_reg2 for a character.
  1416. -			if (RFIFOREST(fd) < 10)
  1417. -				return 0;
  1418. -			else{
  1419. -				struct mmo_account acc;
  1420. -				size_t off;
  1421. -
  1422. -				int account_id = RFIFOL(fd,2);
  1423. -				int char_id = RFIFOL(fd,6);
  1424. -				RFIFOSKIP(fd,10);
  1425. -
  1426. -				WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg));
  1427. -				WFIFOW(fd,0) = 0x2729;
  1428. -				WFIFOL(fd,4) = account_id;
  1429. -				WFIFOL(fd,8) = char_id;
  1430. -				WFIFOB(fd,12) = 1; //Type 1 for Account2 registry
  1431. -
  1432. -				off = 13;
  1433. -				if( accounts->load_num(accounts, &acc, account_id) ){
  1434. -					for( j = 0; j < acc.account_reg2_num; j++ ){
  1435. -						if( acc.account_reg2[j].str[0] != '\0' ){
  1436. -							off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place.
  1437. -							off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1;
  1438. -						}
  1439. -					}
  1440. -				}
  1441. -
  1442. -				WFIFOW(fd,2) = (uint16)off;
  1443. -				WFIFOSET(fd,WFIFOW(fd,2));
  1444. -			}
  1445. -		break;
  1446. -
  1447. -		case 0x2736: // WAN IP update from char-server
  1448. -			if( RFIFOREST(fd) < 6 )
  1449. -				return 0;
  1450. -			server[id].ip = ntohl(RFIFOL(fd,2));
  1451. -			ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip));
  1452. -			RFIFOSKIP(fd,6);
  1453. -		break;
  1454. -
  1455. -		case 0x2737: //Request to set all offline.
  1456. -			ShowInfo("Setting accounts from char-server %d offline.\n", id);
  1457. -			online_db->foreach(online_db, online_db_setoffline, id);
  1458. -			RFIFOSKIP(fd,2);
  1459. -		break;
  1460. -
  1461. -		case 0x2738: //Change PIN Code for a account
  1462. -			if( RFIFOREST(fd) < 11 )
  1463. -				return 0;
  1464. -			else{
  1465. -				struct mmo_account acc;
  1466. -
  1467. -				if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
  1468. -					strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 );
  1469. -					acc.pincode_change = time( NULL );
  1470. -					accounts->save(accounts, &acc);
  1471. -				}
  1472. -
  1473. -				RFIFOSKIP(fd,11);
  1474. -			}
  1475. -		break;
  1476. -
  1477. -		case 0x2739: // PIN Code was entered wrong too often
  1478. -			if( RFIFOREST(fd) < 6 )
  1479. -				return 0;
  1480. -			else{
  1481. -				struct mmo_account acc;
  1482. -
  1483. -				if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
  1484. -					struct online_login_data* ld;
  1485. -
  1486. -					ld = (struct online_login_data*)idb_get(online_db,acc.account_id);
  1487. -
  1488. -					if( ld == NULL )
  1489. -						return 0;
  1490. -
  1491. -					login_log( host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed" );
  1492. -				}
  1493. -
  1494. -				remove_online_user(acc.account_id);
  1495. -
  1496. -				RFIFOSKIP(fd,6);
  1497. -			}
  1498. -		break;
  1499. -
  1500. -		default:
  1501. -			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
  1502. -			set_eof(fd);
  1503. -			return 0;
  1504. -		} // switch
  1505. -	} // while
  1506. -
  1507. -	return 0;
  1508. -}
  1509. -
  1510. -
  1511.  //-------------------------------------
  1512.  // Make new account
  1513.  //-------------------------------------
  1514. @@ -964,7 +167,7 @@
  1515.  	//Account Registration Flood Protection by [Kevin]
  1516.  	if( new_reg_tick == 0 )
  1517.  		new_reg_tick = gettick();
  1518. -	if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) {
  1519. +	if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= login_config.allowed_regs ) {
  1520.  		ShowNotice("Account registration denied (registration limit exceeded)\n");
  1521.  		return 3;
  1522.  	}
  1523. @@ -1004,7 +207,7 @@
  1524.  
  1525.  	if( DIFF_TICK(tick, new_reg_tick) > 0 ) {// Update the registration check.
  1526.  		num_regs = 0;
  1527. -		new_reg_tick = tick + time_allowed*1000;
  1528. +		new_reg_tick = tick + login_config.time_allowed*1000;
  1529.  	}
  1530.  	++num_regs;
  1531.  
  1532. @@ -1041,8 +244,11 @@
  1533.  	}
  1534.  
  1535.  	//Client Version check
  1536. -	if( login_config.check_client_version && sd->version != login_config.client_version_to_connect )
  1537. +	if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ){
  1538. +		ShowNotice("Invalid version (account: '%s', auth_vers: '%d', received version: '%d', ip: %s)\n",
  1539. +			sd->userid, login_config.client_version_to_connect, sd->version, ip);
  1540.  		return 5;
  1541. +	}
  1542.  
  1543.  	len = strnlen(sd->userid, NAME_LENGTH);
  1544.  
  1545. @@ -1093,15 +299,16 @@
  1546.  
  1547.  	if( login_config.client_hash_check && !isServer ) {
  1548.  		struct client_hash_node *node = login_config.client_hash_nodes;
  1549. +		uint8 anyhash[16];
  1550.  		bool match = false;
  1551.  
  1552.  		if( !sd->has_client_hash ) {
  1553.  			ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip);
  1554.  			return 5;
  1555.  		}
  1556. -
  1557. +		memset(anyhash,1,sizeof(anyhash));
  1558.  		while( node ) {
  1559. -			if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) {
  1560. +			if( node->group_id <= acc.group_id && (memcmp(node->hash,anyhash,16)==0 || memcmp(node->hash, sd->client_hash, 16) == 0 ) ){
  1561.  				match = true;
  1562.  				break;
  1563.  			}
  1564. @@ -1145,466 +352,97 @@
  1565.  	return -1; // account OK
  1566.  }
  1567.  
  1568. -void login_auth_ok(struct login_session_data* sd)
  1569. +//-----------------------------------------------------
  1570. +// encrypted/unencrypted password check (from eApp)
  1571. +//-----------------------------------------------------
  1572. +bool check_encrypted(const char* str1, const char* str2, const char* passwd)
  1573.  {
  1574. -	int fd = sd->fd;
  1575. -	uint32 ip = session[fd]->client_addr;
  1576. +	char tmpstr[64+1], md5str[32+1];
  1577.  
  1578. -	uint8 server_num, n;
  1579. -	uint32 subnet_char_ip;
  1580. -	struct auth_node* node;
  1581. -	int i;
  1582. +	safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
  1583. +	MD5_String(tmpstr, md5str);
  1584.  
  1585. -	if( runflag != LOGINSERVER_ST_RUNNING )
  1586. -	{
  1587. -		// players can only login while running
  1588. -		WFIFOHEAD(fd,3);
  1589. -		WFIFOW(fd,0) = 0x81;
  1590. -		WFIFOB(fd,2) = 1;// server closed
  1591. -		WFIFOSET(fd,3);
  1592. -		return;
  1593. -	}
  1594. +	return (0==strcmp(passwd, md5str));
  1595. +}
  1596.  
  1597. -	if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect ) {
  1598. -		ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id);
  1599. -		WFIFOHEAD(fd,3);
  1600. -		WFIFOW(fd,0) = 0x81;
  1601. -		WFIFOB(fd,2) = 1; // 01 = Server closed
  1602. -		WFIFOSET(fd,3);
  1603. -		return;
  1604. -	} else if( login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect ) {
  1605. -		ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id);
  1606. -		WFIFOHEAD(fd,3);
  1607. -		WFIFOW(fd,0) = 0x81;
  1608. -		WFIFOB(fd,2) = 1; // 01 = Server closed
  1609. -		WFIFOSET(fd,3);
  1610. -		return;
  1611. -	}
  1612. -
  1613. -	server_num = 0;
  1614. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  1615. -		if( session_isActive(server[i].fd) )
  1616. -			server_num++;
  1617. -
  1618. -	if( server_num == 0 )
  1619. -	{// if no char-server, don't send void list of servers, just disconnect the player with proper message
  1620. -		ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid);
  1621. -		WFIFOHEAD(fd,3);
  1622. -		WFIFOW(fd,0) = 0x81;
  1623. -		WFIFOB(fd,2) = 1; // 01 = Server closed
  1624. -		WFIFOSET(fd,3);
  1625. -		return;
  1626. -	}
  1627. -
  1628. +bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass)
  1629. +{
  1630. +	if(passwdenc == 0)
  1631.  	{
  1632. -		struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id);
  1633. -		if( data )
  1634. -		{// account is already marked as online!
  1635. -			if( data->char_server > -1 )
  1636. -			{// Request char servers to kick this account out. [Skotlex]
  1637. -				uint8 buf[6];
  1638. -				ShowNotice("User '%s' is already online - Rejected.\n", sd->userid);
  1639. -				WBUFW(buf,0) = 0x2734;
  1640. -				WBUFL(buf,2) = sd->account_id;
  1641. -				charif_sendallwos(-1, buf, 6);
  1642. -				if( data->waiting_disconnect == INVALID_TIMER )
  1643. -					data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0);
  1644. -
  1645. -				WFIFOHEAD(fd,3);
  1646. -				WFIFOW(fd,0) = 0x81;
  1647. -				WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login
  1648. -				WFIFOSET(fd,3);
  1649. -				return;
  1650. -			}
  1651. -			else
  1652. -			if( data->char_server == -1 )
  1653. -			{// client has authed but did not access char-server yet
  1654. -				// wipe previous session
  1655. -				idb_remove(auth_db, sd->account_id);
  1656. -				remove_online_user(sd->account_id);
  1657. -				data = NULL;
  1658. -			}
  1659. -		}
  1660. +		return (0==strcmp(passwd, refpass));
  1661.  	}
  1662. -
  1663. -	login_log(ip, sd->userid, 100, "login ok");
  1664. -	ShowStatus("Connection of the account '%s' accepted.\n", sd->userid);
  1665. -
  1666. -	WFIFOHEAD(fd,47+32*server_num);
  1667. -	WFIFOW(fd,0) = 0x69;
  1668. -	WFIFOW(fd,2) = 47+32*server_num;
  1669. -	WFIFOL(fd,4) = sd->login_id1;
  1670. -	WFIFOL(fd,8) = sd->account_id;
  1671. -	WFIFOL(fd,12) = sd->login_id2;
  1672. -	WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used)
  1673. -	//memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used)
  1674. -	memset(WFIFOP(fd,20), 0, 24);
  1675. -	WFIFOW(fd,44) = 0; // unknown
  1676. -	WFIFOB(fd,46) = sex_str2num(sd->sex);
  1677. -	for( i = 0, n = 0; i < ARRAYLENGTH(server); ++i )
  1678. +	else
  1679.  	{
  1680. -		if( !session_isValid(server[i].fd) )
  1681. -			continue;
  1682. +		// password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
  1683. +		// password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
  1684.  
  1685. -		subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza]
  1686. -		WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip);
  1687. -		WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  1688. -		memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20);
  1689. -		WFIFOW(fd,47+n*32+26) = server[i].users;
  1690. -		WFIFOW(fd,47+n*32+28) = server[i].type;
  1691. -		WFIFOW(fd,47+n*32+30) = server[i].new_;
  1692. -		n++;
  1693. +		return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) ||
  1694. +		       ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd));
  1695.  	}
  1696. -	WFIFOSET(fd,47+32*server_num);
  1697. -
  1698. -	// create temporary auth entry
  1699. -	CREATE(node, struct auth_node, 1);
  1700. -	node->account_id = sd->account_id;
  1701. -	node->login_id1 = sd->login_id1;
  1702. -	node->login_id2 = sd->login_id2;
  1703. -	node->sex = sd->sex;
  1704. -	node->ip = ip;
  1705. -	node->version = sd->version;
  1706. -	node->clienttype = sd->clienttype;
  1707. -	idb_put(auth_db, sd->account_id, node);
  1708. -
  1709. -	{
  1710. -		struct online_login_data* data;
  1711. -
  1712. -		// mark client as 'online'
  1713. -		data = add_online_user(-1, sd->account_id);
  1714. -
  1715. -		// schedule deletion of this node
  1716. -		data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0);
  1717. -	}
  1718.  }
  1719.  
  1720. -/* Log the result of a failed connection attempt by sd
  1721. - * result: nb (msg define in conf)
  1722. -    0 = Unregistered ID
  1723. -    1 = Incorrect Password
  1724. -    2 = This ID is expired
  1725. -    3 = Rejected from Server
  1726. -    4 = You have been blocked by the GM Team
  1727. -    5 = Your Game's EXE file is not the latest version
  1728. -    6 = Your are Prohibited to log in until %s
  1729. -    7 = Server is jammed due to over populated
  1730. -    8 = No more accounts may be connected from this company
  1731. -    9 = MSI_REFUSE_BAN_BY_DBA
  1732. -    10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED
  1733. -    11 = MSI_REFUSE_BAN_BY_GM
  1734. -    12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK
  1735. -    13 = MSI_REFUSE_SELF_LOCK
  1736. -    14 = MSI_REFUSE_NOT_PERMITTED_GROUP
  1737. -    15 = MSI_REFUSE_NOT_PERMITTED_GROUP
  1738. -    99 = This ID has been totally erased
  1739. -    100 = Login information remains at %s
  1740. -    101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information
  1741. -    102 = This account has been temporarily prohibited from login due to a bug-related investigation
  1742. -    103 = This character is being deleted. Login is temporarily unavailable for the time being
  1743. -    104 = This character is being deleted. Login is temporarily unavailable for the time being
  1744. -     default = Unknown Error.
  1745. - */
  1746. -void login_auth_failed(struct login_session_data* sd, int result)
  1747. +//--------------------------------------------
  1748. +// Test to know if an IP come from LAN or WAN.
  1749. +//--------------------------------------------
  1750. +int lan_subnetcheck(uint32 ip)
  1751.  {
  1752. -	int fd = sd->fd;
  1753. -	uint32 ip = session[fd]->client_addr;
  1754. -
  1755. -	if (login_config.log_login)
  1756. -	{
  1757. -		if(result >= 0 && result <= 15)
  1758. -		    login_log(ip, sd->userid, result, msg_txt(result));
  1759. -		else if(result >= 99 && result <= 104)
  1760. -		    login_log(ip, sd->userid, result, msg_txt(result-83)); //-83 offset
  1761. -		else
  1762. -		    login_log(ip, sd->userid, result, msg_txt(22)); //unknow error
  1763. -	}
  1764. -
  1765. -	if( result == 1 && login_config.dynamic_pass_failure_ban )
  1766. -		ipban_log(ip); // log failed password attempt
  1767. -
  1768. -#if PACKETVER >= 20120000 /* not sure when this started */
  1769. -	WFIFOHEAD(fd,26);
  1770. -	WFIFOW(fd,0) = 0x83e;
  1771. -	WFIFOL(fd,2) = result;
  1772. -	if( result != 6 )
  1773. -		memset(WFIFOP(fd,6), '\0', 20);
  1774. -	else { // 6 = Your are Prohibited to log in until %s
  1775. -		struct mmo_account acc;
  1776. -		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
  1777. -		timestamp2string((char*)WFIFOP(fd,6), 20, unban_time, login_config.date_format);
  1778. -	}
  1779. -	WFIFOSET(fd,26);
  1780. -#else
  1781. -	WFIFOHEAD(fd,23);
  1782. -	WFIFOW(fd,0) = 0x6a;
  1783. -	WFIFOB(fd,2) = (uint8)result;
  1784. -	if( result != 6 )
  1785. -		memset(WFIFOP(fd,3), '\0', 20);
  1786. -	else { // 6 = Your are Prohibited to log in until %s
  1787. -		struct mmo_account acc;
  1788. -		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
  1789. -		timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format);
  1790. -	}
  1791. -	WFIFOSET(fd,23);
  1792. -#endif
  1793. +	int i;
  1794. +	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  1795. +	return ( i < subnet_count ) ? subnet[i].char_ip : 0;
  1796.  }
  1797.  
  1798. -
  1799. -//----------------------------------------------------------------------------------------
  1800. -// Default packet parsing (normal players or char-server connection requests)
  1801. -//----------------------------------------------------------------------------------------
  1802. -int parse_login(int fd)
  1803. +//----------------------------------
  1804. +// Reading Lan Support configuration
  1805. +//----------------------------------
  1806. +int login_lan_config_read(const char *lancfgName)
  1807.  {
  1808. -	struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data;
  1809. -	int result;
  1810. +	FILE *fp;
  1811. +	int line_num = 0;
  1812. +	char line[1024], w1[64], w2[64], w3[64], w4[64];
  1813.  
  1814. -	char ip[16];
  1815. -	uint32 ipl = session[fd]->client_addr;
  1816. -	ip2str(ipl, ip);
  1817. -
  1818. -	if( session[fd]->flag.eof )
  1819. -	{
  1820. -		ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip);
  1821. -		do_close(fd);
  1822. -		return 0;
  1823. +	if((fp = fopen(lancfgName, "r")) == NULL) {
  1824. +		ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
  1825. +		return 1;
  1826.  	}
  1827.  
  1828. -	if( sd == NULL )
  1829. +	while(fgets(line, sizeof(line), fp))
  1830.  	{
  1831. -		// Perform ip-ban check
  1832. -		if( login_config.ipban && ipban_check(ipl) )
  1833. -		{
  1834. -			ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip);
  1835. -			login_log(ipl, "unknown", -3, "ip banned");
  1836. -			WFIFOHEAD(fd,23);
  1837. -			WFIFOW(fd,0) = 0x6a;
  1838. -			WFIFOB(fd,2) = 3; // 3 = Rejected from Server
  1839. -			WFIFOSET(fd,23);
  1840. -			set_eof(fd);
  1841. -			return 0;
  1842. -		}
  1843. +		line_num++;
  1844. +		if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
  1845. +			continue;
  1846.  
  1847. -		// create a session for this new connection
  1848. -		CREATE(session[fd]->session_data, struct login_session_data, 1);
  1849. -		sd = (struct login_session_data*)session[fd]->session_data;
  1850. -		sd->fd = fd;
  1851. -	}
  1852. -
  1853. -	while( RFIFOREST(fd) >= 2 )
  1854. -	{
  1855. -		uint16 command = RFIFOW(fd,0);
  1856. -
  1857. -		switch( command )
  1858. +		if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4)
  1859.  		{
  1860. -
  1861. -		case 0x0200:		// New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
  1862. -			if (RFIFOREST(fd) < 26)
  1863. -				return 0;
  1864. -			RFIFOSKIP(fd,26);
  1865. -		break;
  1866. -
  1867. -		// client md5 hash (binary)
  1868. -		case 0x0204: // S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6)
  1869. -			if (RFIFOREST(fd) < 18)
  1870. -				return 0;
  1871. -
  1872. -			sd->has_client_hash = 1;
  1873. -			memcpy(sd->client_hash, RFIFOP(fd, 2), 16);
  1874. -
  1875. -			RFIFOSKIP(fd,18);
  1876. -		break;
  1877. -
  1878. -		// request client login (raw password)
  1879. -		case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
  1880. -		case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
  1881. -		case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
  1882. -		// request client login (md5-hashed password)
  1883. -		case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
  1884. -		case 0x01fa: // S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
  1885. -		case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
  1886. -		case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
  1887. -		{
  1888. -			size_t packet_len = RFIFOREST(fd);
  1889. -
  1890. -			if( (command == 0x0064 && packet_len < 55)
  1891. -			||  (command == 0x0277 && packet_len < 84)
  1892. -			||  (command == 0x02b0 && packet_len < 85)
  1893. -			||  (command == 0x01dd && packet_len < 47)
  1894. -			||  (command == 0x01fa && packet_len < 48)
  1895. -			||  (command == 0x027c && packet_len < 60)
  1896. -			||  (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) )
  1897. -				return 0;
  1898. +			ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
  1899. +			continue;
  1900.  		}
  1901. -		{
  1902. -			uint32 version;
  1903. -			char username[NAME_LENGTH];
  1904. -			char password[NAME_LENGTH];
  1905. -			unsigned char passhash[16];
  1906. -			uint8 clienttype;
  1907. -			bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825);
  1908.  
  1909. -			// Shinryo: For the time being, just use token as password.
  1910. -			if(command == 0x0825)
  1911. -			{
  1912. -				char *accname = (char *)RFIFOP(fd, 9);
  1913. -				char *token = (char *)RFIFOP(fd, 0x5C);
  1914. -				size_t uAccLen = strlen(accname);
  1915. -				size_t uTokenLen = RFIFOREST(fd) - 0x5C;
  1916. -
  1917. -				version = RFIFOL(fd,4);
  1918. -
  1919. -				if(uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1  || uTokenLen <= 0)
  1920. -				{
  1921. -					login_auth_failed(sd, 3);
  1922. -					return 0;
  1923. -				}
  1924. -
  1925. -				safestrncpy(username, accname, uAccLen + 1);
  1926. -				safestrncpy(password, token, uTokenLen + 1);
  1927. -				clienttype = RFIFOB(fd, 8);
  1928. -			}
  1929. -			else
  1930. -			{
  1931. -				version = RFIFOL(fd,2);
  1932. -				safestrncpy(username, (const char*)RFIFOP(fd,6), NAME_LENGTH);
  1933. -				if( israwpass )
  1934. -				{
  1935. -					safestrncpy(password, (const char*)RFIFOP(fd,30), NAME_LENGTH);
  1936. -					clienttype = RFIFOB(fd,54);
  1937. -				}
  1938. -				else
  1939. -				{
  1940. -					memcpy(passhash, RFIFOP(fd,30), 16);
  1941. -					clienttype = RFIFOB(fd,46);
  1942. -				}
  1943. -			}
  1944. -			RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent
  1945. -
  1946. -			sd->clienttype = clienttype;
  1947. -			sd->version = version;
  1948. -			safestrncpy(sd->userid, username, NAME_LENGTH);
  1949. -			if( israwpass )
  1950. -			{
  1951. -				ShowStatus("Request for connection of %s (ip: %s) version=%d\n", sd->userid, ip,sd->version);
  1952. -				safestrncpy(sd->passwd, password, NAME_LENGTH);
  1953. -				if( login_config.use_md5_passwds )
  1954. -					MD5_String(sd->passwd, sd->passwd);
  1955. -				sd->passwdenc = 0;
  1956. -			}
  1957. -			else
  1958. -			{
  1959. -				ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s) version=%d\n", sd->userid, ip,sd->version);
  1960. -				bin2hex(sd->passwd, passhash, 16); // raw binary data here!
  1961. -				sd->passwdenc = PASSWORDENC;
  1962. -			}
  1963. -
  1964. -			if( sd->passwdenc != 0 && login_config.use_md5_passwds )
  1965. -			{
  1966. -				login_auth_failed(sd, 3); // send "rejected from server"
  1967. -				return 0;
  1968. -			}
  1969. -
  1970. -			result = mmo_auth(sd, false);
  1971. -
  1972. -			if( result == -1 )
  1973. -				login_auth_ok(sd);
  1974. -			else
  1975. -				login_auth_failed(sd, result);
  1976. -		}
  1977. -		break;
  1978. -
  1979. -		case 0x01db:	// Sending request of the coding key
  1980. -			RFIFOSKIP(fd,2);
  1981. +		if( strcmpi(w1, "subnet") == 0 )
  1982.  		{
  1983. -			memset(sd->md5key, '\0', sizeof(sd->md5key));
  1984. -			sd->md5keylen = (uint16)(12 + rnd() % 4);
  1985. -			MD5_Salt(sd->md5keylen, sd->md5key);
  1986. +			subnet[subnet_count].mask = str2ip(w2);
  1987. +			subnet[subnet_count].char_ip = str2ip(w3);
  1988. +			subnet[subnet_count].map_ip = str2ip(w4);
  1989.  
  1990. -			WFIFOHEAD(fd,4 + sd->md5keylen);
  1991. -			WFIFOW(fd,0) = 0x01dc;
  1992. -			WFIFOW(fd,2) = 4 + sd->md5keylen;
  1993. -			memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen);
  1994. -			WFIFOSET(fd,WFIFOW(fd,2));
  1995. -		}
  1996. -		break;
  1997. -
  1998. -		case 0x2710:	// Connection request of a char-server
  1999. -			if (RFIFOREST(fd) < 86)
  2000. -				return 0;
  2001. -		{
  2002. -			char server_name[20];
  2003. -			char message[256];
  2004. -			uint32 server_ip;
  2005. -			uint16 server_port;
  2006. -			uint16 type;
  2007. -			uint16 new_;
  2008. -
  2009. -			safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH);
  2010. -			safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH);
  2011. -			if( login_config.use_md5_passwds )
  2012. -				MD5_String(sd->passwd, sd->passwd);
  2013. -			sd->passwdenc = 0;
  2014. -			sd->version = login_config.client_version_to_connect; // hack to skip version check
  2015. -			server_ip = ntohl(RFIFOL(fd,54));
  2016. -			server_port = ntohs(RFIFOW(fd,58));
  2017. -			safestrncpy(server_name, (char*)RFIFOP(fd,60), 20);
  2018. -			type = RFIFOW(fd,82);
  2019. -			new_ = RFIFOW(fd,84);
  2020. -			RFIFOSKIP(fd,86);
  2021. -
  2022. -			ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip);
  2023. -			sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port);
  2024. -			login_log(session[fd]->client_addr, sd->userid, 100, message);
  2025. -
  2026. -			result = mmo_auth(sd, true);
  2027. -			if( runflag == LOGINSERVER_ST_RUNNING &&
  2028. -				result == -1 &&
  2029. -				sd->sex == 'S' &&
  2030. -				sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) &&
  2031. -				!session_isValid(server[sd->account_id].fd) )
  2032. +			if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
  2033.  			{
  2034. -				ShowStatus("Connection of the char-server '%s' accepted.\n", server_name);
  2035. -				safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name));
  2036. -				server[sd->account_id].fd = fd;
  2037. -				server[sd->account_id].ip = server_ip;
  2038. -				server[sd->account_id].port = server_port;
  2039. -				server[sd->account_id].users = 0;
  2040. -				server[sd->account_id].type = type;
  2041. -				server[sd->account_id].new_ = new_;
  2042. -
  2043. -				session[fd]->func_parse = parse_fromchar;
  2044. -				session[fd]->flag.server = 1;
  2045. -				realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  2046. -
  2047. -				// send connection success
  2048. -				WFIFOHEAD(fd,3);
  2049. -				WFIFOW(fd,0) = 0x2711;
  2050. -				WFIFOB(fd,2) = 0;
  2051. -				WFIFOSET(fd,3);
  2052. +				ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
  2053. +				continue;
  2054.  			}
  2055. -			else
  2056. -			{
  2057. -				ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name);
  2058. -				WFIFOHEAD(fd,3);
  2059. -				WFIFOW(fd,0) = 0x2711;
  2060. -				WFIFOB(fd,2) = 3;
  2061. -				WFIFOSET(fd,3);
  2062. -			}
  2063. -		}
  2064. -		return 0; // processing will continue elsewhere
  2065.  
  2066. -		default:
  2067. -			ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command);
  2068. -			set_eof(fd);
  2069. -			return 0;
  2070. +			subnet_count++;
  2071.  		}
  2072.  	}
  2073.  
  2074. +	if( subnet_count > 1 ) /* only useful if there is more than 1 available */
  2075. +		ShowStatus("Read information about %d subnetworks.\n", subnet_count);
  2076. +
  2077. +	fclose(fp);
  2078.  	return 0;
  2079.  }
  2080.  
  2081. -
  2082. +/*
  2083. + * Init default configuration
  2084. + */
  2085.  void login_set_defaults()
  2086.  {
  2087.  	login_config.login_ip = INADDR_ANY;
  2088. @@ -1620,7 +458,8 @@
  2089.  	login_config.group_id_to_connect = -1;
  2090.  	login_config.min_group_id_to_connect = -1;
  2091.  	login_config.check_client_version = false;
  2092. -	login_config.client_version_to_connect = 20;
  2093. +	login_config.client_version_to_connect = date2version(PACKETVER); //20120410 => 30
  2094. +	ShowInfo("loginconfig: client_version_to_connect = %d\n",login_config.client_version_to_connect);
  2095.  
  2096.  	login_config.ipban = true;
  2097.  	login_config.dynamic_pass_failure_ban = true;
  2098. @@ -1630,9 +469,16 @@
  2099.  	login_config.use_dnsbl = false;
  2100.  	safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs));
  2101.  	safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine));
  2102. +	login_config.allowed_regs = true;
  2103. +	login_config.time_allowed = 10; //in second
  2104.  
  2105.  	login_config.client_hash_check = 0;
  2106.  	login_config.client_hash_nodes = NULL;
  2107. +
  2108. +	//other default conf
  2109. +	login_config.loginconf_name = "conf/login_athena.conf";
  2110. +	login_config.lanconf_name = "conf/subnet_athena.conf";
  2111. +	login_config.msgconf_name = "conf/msg_conf/login_msg.conf";
  2112.  }
  2113.  
  2114.  //-----------------------------------
  2115. @@ -1696,9 +542,9 @@
  2116.  		else if(!strcmpi(w1, "console"))
  2117.  			login_config.console = (bool)config_switch(w2);
  2118.  		else if(!strcmpi(w1, "allowed_regs")) //account flood protection system
  2119. -			allowed_regs = atoi(w2);
  2120. +			login_config.allowed_regs = atoi(w2);
  2121.  		else if(!strcmpi(w1, "time_allowed"))
  2122. -			time_allowed = atoi(w2);
  2123. +			login_config.time_allowed = atoi(w2);
  2124.  		else if(!strcmpi(w1, "use_dnsbl"))
  2125.  			login_config.use_dnsbl = (bool)config_switch(w2);
  2126.  		else if(!strcmpi(w1, "dnsbl_servers"))
  2127. @@ -1718,15 +564,20 @@
  2128.  				int i;
  2129.  				CREATE(nnode, struct client_hash_node, 1);
  2130.  
  2131. -				for (i = 0; i < 32; i += 2) {
  2132. -					char buf[3];
  2133. -					unsigned int byte;
  2134. +				if(!strcmpi(md5,"any")){
  2135. +					memset(nnode->hash,1,sizeof(nnode->hash));
  2136. +				}
  2137. +				else {
  2138. +					for (i = 0; i < 32; i += 2) {
  2139. +						char buf[3];
  2140. +						unsigned int byte;
  2141.  
  2142. -					memcpy(buf, &md5[i], 2);
  2143. -					buf[2] = 0;
  2144. +						memcpy(buf, &md5[i], 2);
  2145. +						buf[2] = 0;
  2146.  
  2147. -					sscanf(buf, "%x", &byte);
  2148. -					nnode->hash[i / 2] = (uint8)(byte & 0xFF);
  2149. +						sscanf(buf, "%x", &byte);
  2150. +						nnode->hash[i / 2] = (uint8)(byte & 0xFF);
  2151. +					}
  2152.  				}
  2153.  
  2154.  				nnode->group_id = group;
  2155. @@ -1818,8 +669,7 @@
  2156.  	online_db->destroy(online_db, NULL);
  2157.  	auth_db->destroy(auth_db, NULL);
  2158.  
  2159. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  2160. -		chrif_server_destroy(i);
  2161. +	do_final_loginchrif();
  2162.  
  2163.  	if( login_fd != -1 )
  2164.  	{
  2165. @@ -1849,12 +699,10 @@
  2166.  {
  2167.  	if( runflag != LOGINSERVER_ST_SHUTDOWN )
  2168.  	{
  2169. -		int id;
  2170.  		runflag = LOGINSERVER_ST_SHUTDOWN;
  2171.  		ShowStatus("Shutting down...\n");
  2172.  		// TODO proper shutdown procedure; kick all characters, wait for acks, ...  [FlavioJS]
  2173. -		for( id = 0; id < ARRAYLENGTH(server); ++id )
  2174. -			chrif_server_reset(id);
  2175. +		do_shutdown_loginchrif();
  2176.  		flush_fifos();
  2177.  		runflag = CORE_ST_STOP;
  2178.  	}
  2179. @@ -1874,21 +722,16 @@
  2180.  
  2181.  	// read login-server configuration
  2182.  	login_set_defaults();
  2183. +	cnsl_get_options(argc,argv);
  2184.  
  2185. -	LOGIN_CONF_NAME = "conf/login_athena.conf";
  2186. -	LAN_CONF_NAME = "conf/subnet_athena.conf";
  2187. -	MSG_CONF_NAME_EN = "conf/msg_conf/login_msg.conf";
  2188. +	login_config_read(login_config.loginconf_name);
  2189. +	msg_config_read(login_config.msgconf_name);
  2190. +	login_lan_config_read(login_config.lanconf_name);
  2191. +	//end config
  2192.  
  2193. -	cli_get_options(argc,argv);
  2194. -
  2195. -	msg_config_read(MSG_CONF_NAME_EN);
  2196. -	login_config_read(LOGIN_CONF_NAME);
  2197. -	login_lan_config_read(LAN_CONF_NAME);
  2198. -
  2199.  	rnd_init();
  2200.  
  2201. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  2202. -		chrif_server_init(i);
  2203. +	do_init_loginchrif();
  2204.  
  2205.  	// initialize logging
  2206.  	if( login_config.log_login )
  2207. @@ -1911,12 +754,6 @@
  2208.  	add_timer_func_list(online_data_cleanup, "online_data_cleanup");
  2209.  	add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000);
  2210.  
  2211. -	// add timer to detect ip address change and perform update
  2212. -	if (login_config.ip_sync_interval) {
  2213. -		add_timer_func_list(sync_ip_addresses, "sync_ip_addresses");
  2214. -		add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval);
  2215. -	}
  2216. -
  2217.  	// Account database init
  2218.  	accounts = get_account_engine();
  2219.  	if( accounts == NULL ) {
  2220. @@ -1941,14 +778,11 @@
  2221.  		runflag = LOGINSERVER_ST_RUNNING;
  2222.  	}
  2223.  
  2224. +	do_init_logincnslif();
  2225. +
  2226.  	ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port);
  2227.  	login_log(0, "login server", 100, "login server started");
  2228.  
  2229. -	if( login_config.console ) {
  2230. -		add_timer_func_list(parse_console_timer, "parse_console_timer");
  2231. -		add_timer_interval(gettick()+1000, parse_console_timer, 0, 0, 1000); //start in 1s each 1sec
  2232. -	}
  2233. -
  2234.  	return 0;
  2235.  }
  2236.  
  2237. @@ -1961,21 +795,3 @@
  2238.  void login_do_final_msg(void){
  2239.  	_do_final_msg(LOGIN_MAX_MSG,msg_table);
  2240.  }
  2241. -
  2242. -/*======================================================
  2243. - * Login-Server help option info
  2244. - *------------------------------------------------------*/
  2245. -void display_helpscreen(bool do_exit)
  2246. -{
  2247. -	ShowInfo("Usage: %s [options]\n", SERVER_NAME);
  2248. -	ShowInfo("\n");
  2249. -	ShowInfo("Options:\n");
  2250. -	ShowInfo("  -?, -h [--help]\t\tDisplays this help screen.\n");
  2251. -	ShowInfo("  -v [--version]\t\tDisplays the server's version.\n");
  2252. -	ShowInfo("  --run-once\t\t\tCloses server after loading (testing).\n");
  2253. -	ShowInfo("  --login-config <file>\t\tAlternative login-server configuration.\n");
  2254. -	ShowInfo("  --lan-config <file>\t\tAlternative lag configuration.\n");
  2255. -	ShowInfo("  --msg-config <file>\t\tAlternative message configuration.\n");
  2256. -	if( do_exit )
  2257. -		exit(EXIT_SUCCESS);
  2258. -}
  2259. Index: src/login/account_sql.c
  2260. ===================================================================
  2261. --- src/login/account_sql.c	(revision 17365)
  2262. +++ src/login/account_sql.c	(working copy)
  2263. @@ -1,689 +0,0 @@
  2264. -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2265. -// For more information, see LICENCE in the main folder
  2266. -
  2267. -#include "../common/malloc.h"
  2268. -#include "../common/mmo.h"
  2269. -#include "../common/showmsg.h"
  2270. -#include "../common/sql.h"
  2271. -#include "../common/strlib.h"
  2272. -#include "../common/timer.h"
  2273. -#include "account.h"
  2274. -#include <stdlib.h>
  2275. -#include <string.h>
  2276. -
  2277. -/// global defines
  2278. -#define ACCOUNT_SQL_DB_VERSION 20110114
  2279. -
  2280. -/// internal structure
  2281. -typedef struct AccountDB_SQL
  2282. -{
  2283. -	AccountDB vtable;    // public interface
  2284. -
  2285. -	Sql* accounts;       // SQL accounts storage
  2286. -
  2287. -	// global sql settings
  2288. -	char   global_db_hostname[32];
  2289. -	uint16 global_db_port;
  2290. -	char   global_db_username[32];
  2291. -	char   global_db_password[32];
  2292. -	char   global_db_database[32];
  2293. -	char   global_codepage[32];
  2294. -	// local sql settings
  2295. -	char   db_hostname[32];
  2296. -	uint16 db_port;
  2297. -	char   db_username[32];
  2298. -	char   db_password[32];
  2299. -	char   db_database[32];
  2300. -	char   codepage[32];
  2301. -	// other settings
  2302. -	bool case_sensitive;
  2303. -	char account_db[32];
  2304. -	char accreg_db[32];
  2305. -
  2306. -} AccountDB_SQL;
  2307. -
  2308. -/// internal structure
  2309. -typedef struct AccountDBIterator_SQL
  2310. -{
  2311. -	AccountDBIterator vtable;    // public interface
  2312. -
  2313. -	AccountDB_SQL* db;
  2314. -	int last_account_id;
  2315. -} AccountDBIterator_SQL;
  2316. -
  2317. -/// internal functions
  2318. -static bool account_db_sql_init(AccountDB* self);
  2319. -static void account_db_sql_destroy(AccountDB* self);
  2320. -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen);
  2321. -static bool account_db_sql_set_property(AccountDB* self, const char* option, const char* value);
  2322. -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc);
  2323. -static bool account_db_sql_remove(AccountDB* self, const int account_id);
  2324. -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc);
  2325. -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id);
  2326. -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid);
  2327. -static AccountDBIterator* account_db_sql_iterator(AccountDB* self);
  2328. -static void account_db_sql_iter_destroy(AccountDBIterator* self);
  2329. -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc);
  2330. -
  2331. -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id);
  2332. -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new);
  2333. -
  2334. -/// public constructor
  2335. -AccountDB* account_db_sql(void)
  2336. -{
  2337. -	AccountDB_SQL* db = (AccountDB_SQL*)aCalloc(1, sizeof(AccountDB_SQL));
  2338. -
  2339. -	// set up the vtable
  2340. -	db->vtable.init         = &account_db_sql_init;
  2341. -	db->vtable.destroy      = &account_db_sql_destroy;
  2342. -	db->vtable.get_property = &account_db_sql_get_property;
  2343. -	db->vtable.set_property = &account_db_sql_set_property;
  2344. -	db->vtable.save         = &account_db_sql_save;
  2345. -	db->vtable.create       = &account_db_sql_create;
  2346. -	db->vtable.remove       = &account_db_sql_remove;
  2347. -	db->vtable.load_num     = &account_db_sql_load_num;
  2348. -	db->vtable.load_str     = &account_db_sql_load_str;
  2349. -	db->vtable.iterator     = &account_db_sql_iterator;
  2350. -
  2351. -	// initialize to default values
  2352. -	db->accounts = NULL;
  2353. -	// global sql settings
  2354. -	safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname));
  2355. -	db->global_db_port = 3306;
  2356. -	safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username));
  2357. -	safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password));
  2358. -	safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database));
  2359. -	safestrncpy(db->global_codepage, "", sizeof(db->global_codepage));
  2360. -	// local sql settings
  2361. -	safestrncpy(db->db_hostname, "", sizeof(db->db_hostname));
  2362. -	db->db_port = 3306;
  2363. -	safestrncpy(db->db_username, "", sizeof(db->db_username));
  2364. -	safestrncpy(db->db_password, "", sizeof(db->db_password));
  2365. -	safestrncpy(db->db_database, "", sizeof(db->db_database));
  2366. -	safestrncpy(db->codepage, "", sizeof(db->codepage));
  2367. -	// other settings
  2368. -	db->case_sensitive = false;
  2369. -	safestrncpy(db->account_db, "login", sizeof(db->account_db));
  2370. -	safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db));
  2371. -
  2372. -	return &db->vtable;
  2373. -}
  2374. -
  2375. -
  2376. -/* ------------------------------------------------------------------------- */
  2377. -
  2378. -
  2379. -/// establishes database connection
  2380. -static bool account_db_sql_init(AccountDB* self)
  2381. -{
  2382. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2383. -	Sql* sql_handle;
  2384. -	const char* username;
  2385. -	const char* password;
  2386. -	const char* hostname;
  2387. -	uint16      port;
  2388. -	const char* database;
  2389. -	const char* codepage;
  2390. -
  2391. -	db->accounts = Sql_Malloc();
  2392. -	sql_handle = db->accounts;
  2393. -
  2394. -	if( db->db_hostname[0] != '\0' )
  2395. -	{// local settings
  2396. -		username = db->db_username;
  2397. -		password = db->db_password;
  2398. -		hostname = db->db_hostname;
  2399. -		port     = db->db_port;
  2400. -		database = db->db_database;
  2401. -		codepage = db->codepage;
  2402. -	}
  2403. -	else
  2404. -	{// global settings
  2405. -		username = db->global_db_username;
  2406. -		password = db->global_db_password;
  2407. -		hostname = db->global_db_hostname;
  2408. -		port     = db->global_db_port;
  2409. -		database = db->global_db_database;
  2410. -		codepage = db->global_codepage;
  2411. -	}
  2412. -
  2413. -	if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
  2414. -	{
  2415. -		Sql_ShowDebug(sql_handle);
  2416. -		Sql_Free(db->accounts);
  2417. -		db->accounts = NULL;
  2418. -		return false;
  2419. -	}
  2420. -
  2421. -	if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
  2422. -		Sql_ShowDebug(sql_handle);
  2423. -
  2424. -	return true;
  2425. -}
  2426. -
  2427. -/// disconnects from database
  2428. -static void account_db_sql_destroy(AccountDB* self)
  2429. -{
  2430. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2431. -
  2432. -	Sql_Free(db->accounts);
  2433. -	db->accounts = NULL;
  2434. -	aFree(db);
  2435. -}
  2436. -
  2437. -/// Gets a property from this database.
  2438. -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen)
  2439. -{
  2440. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2441. -	const char* signature;
  2442. -
  2443. -	signature = "engine.";
  2444. -	if( strncmpi(key, signature, strlen(signature)) == 0 )
  2445. -	{
  2446. -		key += strlen(signature);
  2447. -		if( strcmpi(key, "name") == 0 )
  2448. -			safesnprintf(buf, buflen, "sql");
  2449. -		else
  2450. -		if( strcmpi(key, "version") == 0 )
  2451. -			safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION);
  2452. -		else
  2453. -		if( strcmpi(key, "comment") == 0 )
  2454. -			safesnprintf(buf, buflen, "SQL Account Database");
  2455. -		else
  2456. -			return false;// not found
  2457. -		return true;
  2458. -	}
  2459. -
  2460. -	signature = "sql.";
  2461. -	if( strncmpi(key, signature, strlen(signature)) == 0 )
  2462. -	{
  2463. -		key += strlen(signature);
  2464. -		if( strcmpi(key, "db_hostname") == 0 )
  2465. -			safesnprintf(buf, buflen, "%s", db->global_db_hostname);
  2466. -		else
  2467. -		if( strcmpi(key, "db_port") == 0 )
  2468. -			safesnprintf(buf, buflen, "%d", db->global_db_port);
  2469. -		else
  2470. -		if( strcmpi(key, "db_username") == 0 )
  2471. -			safesnprintf(buf, buflen, "%s", db->global_db_username);
  2472. -		else
  2473. -		if(	strcmpi(key, "db_password") == 0 )
  2474. -			safesnprintf(buf, buflen, "%s", db->global_db_password);
  2475. -		else
  2476. -		if( strcmpi(key, "db_database") == 0 )
  2477. -			safesnprintf(buf, buflen, "%s", db->global_db_database);
  2478. -		else
  2479. -		if( strcmpi(key, "codepage") == 0 )
  2480. -			safesnprintf(buf, buflen, "%s", db->global_codepage);
  2481. -		else
  2482. -			return false;// not found
  2483. -		return true;
  2484. -	}
  2485. -
  2486. -	signature = "account.sql.";
  2487. -	if( strncmpi(key, signature, strlen(signature)) == 0 )
  2488. -	{
  2489. -		key += strlen(signature);
  2490. -		if( strcmpi(key, "db_hostname") == 0 )
  2491. -			safesnprintf(buf, buflen, "%s", db->db_hostname);
  2492. -		else
  2493. -		if( strcmpi(key, "db_port") == 0 )
  2494. -			safesnprintf(buf, buflen, "%d", db->db_port);
  2495. -		else
  2496. -		if( strcmpi(key, "db_username") == 0 )
  2497. -			safesnprintf(buf, buflen, "%s", db->db_username);
  2498. -		else
  2499. -		if(	strcmpi(key, "db_password") == 0 )
  2500. -			safesnprintf(buf, buflen, "%s", db->db_password);
  2501. -		else
  2502. -		if( strcmpi(key, "db_database") == 0 )
  2503. -			safesnprintf(buf, buflen, "%s", db->db_database);
  2504. -		else
  2505. -		if( strcmpi(key, "codepage") == 0 )
  2506. -			safesnprintf(buf, buflen, "%s", db->codepage);
  2507. -		else
  2508. -		if( strcmpi(key, "case_sensitive") == 0 )
  2509. -			safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0));
  2510. -		else
  2511. -		if( strcmpi(key, "account_db") == 0 )
  2512. -			safesnprintf(buf, buflen, "%s", db->account_db);
  2513. -		else
  2514. -		if( strcmpi(key, "accreg_db") == 0 )
  2515. -			safesnprintf(buf, buflen, "%s", db->accreg_db);
  2516. -		else
  2517. -			return false;// not found
  2518. -		return true;
  2519. -	}
  2520. -
  2521. -	return false;// not found
  2522. -}
  2523. -
  2524. -/// if the option is supported, adjusts the internal state
  2525. -static bool account_db_sql_set_property(AccountDB* self, const char* key, const char* value)
  2526. -{
  2527. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2528. -	const char* signature;
  2529. -
  2530. -
  2531. -	signature = "sql.";
  2532. -	if( strncmp(key, signature, strlen(signature)) == 0 )
  2533. -	{
  2534. -		key += strlen(signature);
  2535. -		if( strcmpi(key, "db_hostname") == 0 )
  2536. -			safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname));
  2537. -		else
  2538. -		if( strcmpi(key, "db_port") == 0 )
  2539. -			db->global_db_port = (uint16)strtoul(value, NULL, 10);
  2540. -		else
  2541. -		if( strcmpi(key, "db_username") == 0 )
  2542. -			safestrncpy(db->global_db_username, value, sizeof(db->global_db_username));
  2543. -		else
  2544. -		if( strcmpi(key, "db_password") == 0 )
  2545. -			safestrncpy(db->global_db_password, value, sizeof(db->global_db_password));
  2546. -		else
  2547. -		if( strcmpi(key, "db_database") == 0 )
  2548. -			safestrncpy(db->global_db_database, value, sizeof(db->global_db_database));
  2549. -		else
  2550. -		if( strcmpi(key, "codepage") == 0 )
  2551. -			safestrncpy(db->global_codepage, value, sizeof(db->global_codepage));
  2552. -		else
  2553. -			return false;// not found
  2554. -		return true;
  2555. -	}
  2556. -
  2557. -	signature = "account.sql.";
  2558. -	if( strncmp(key, signature, strlen(signature)) == 0 )
  2559. -	{
  2560. -		key += strlen(signature);
  2561. -		if( strcmpi(key, "db_hostname") == 0 )
  2562. -			safestrncpy(db->db_hostname, value, sizeof(db->db_hostname));
  2563. -		else
  2564. -		if( strcmpi(key, "db_port") == 0 )
  2565. -			db->db_port = (uint16)strtoul(value, NULL, 10);
  2566. -		else
  2567. -		if( strcmpi(key, "db_username") == 0 )
  2568. -			safestrncpy(db->db_username, value, sizeof(db->db_username));
  2569. -		else
  2570. -		if( strcmpi(key, "db_password") == 0 )
  2571. -			safestrncpy(db->db_password, value, sizeof(db->db_password));
  2572. -		else
  2573. -		if( strcmpi(key, "db_database") == 0 )
  2574. -			safestrncpy(db->db_database, value, sizeof(db->db_database));
  2575. -		else
  2576. -		if( strcmpi(key, "codepage") == 0 )
  2577. -			safestrncpy(db->codepage, value, sizeof(db->codepage));
  2578. -		else
  2579. -		if( strcmpi(key, "case_sensitive") == 0 )
  2580. -			db->case_sensitive = config_switch(value);
  2581. -		else
  2582. -		if( strcmpi(key, "account_db") == 0 )
  2583. -			safestrncpy(db->account_db, value, sizeof(db->account_db));
  2584. -		else
  2585. -		if( strcmpi(key, "accreg_db") == 0 )
  2586. -			safestrncpy(db->accreg_db, value, sizeof(db->accreg_db));
  2587. -		else
  2588. -			return false;// not found
  2589. -		return true;
  2590. -	}
  2591. -
  2592. -	return false;// not found
  2593. -}
  2594. -
  2595. -/// create a new account entry
  2596. -/// If acc->account_id is -1, the account id will be auto-generated,
  2597. -/// and its value will be written to acc->account_id if everything succeeds.
  2598. -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc)
  2599. -{
  2600. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2601. -	Sql* sql_handle = db->accounts;
  2602. -
  2603. -	// decide on the account id to assign
  2604. -	int account_id;
  2605. -	if( acc->account_id != -1 )
  2606. -	{// caller specifies it manually
  2607. -		account_id = acc->account_id;
  2608. -	}
  2609. -	else
  2610. -	{// ask the database
  2611. -		char* data;
  2612. -		size_t len;
  2613. -
  2614. -		if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db) )
  2615. -		{
  2616. -			Sql_ShowDebug(sql_handle);
  2617. -			return false;
  2618. -		}
  2619. -		if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  2620. -		{
  2621. -			Sql_ShowDebug(sql_handle);
  2622. -			Sql_FreeResult(sql_handle);
  2623. -			return false;
  2624. -		}
  2625. -
  2626. -		Sql_GetData(sql_handle, 0, &data, &len);
  2627. -		account_id = ( data != NULL ) ? atoi(data) : 0;
  2628. -		Sql_FreeResult(sql_handle);
  2629. -
  2630. -		if( account_id < START_ACCOUNT_NUM )
  2631. -			account_id = START_ACCOUNT_NUM;
  2632. -
  2633. -	}
  2634. -
  2635. -	// zero value is prohibited
  2636. -	if( account_id == 0 )
  2637. -		return false;
  2638. -
  2639. -	// absolute maximum
  2640. -	if( account_id > END_ACCOUNT_NUM )
  2641. -		return false;
  2642. -
  2643. -	// insert the data into the database
  2644. -	acc->account_id = account_id;
  2645. -	return mmo_auth_tosql(db, acc, true);
  2646. -}
  2647. -
  2648. -/// delete an existing account entry + its regs
  2649. -static bool account_db_sql_remove(AccountDB* self, const int account_id)
  2650. -{
  2651. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2652. -	Sql* sql_handle = db->accounts;
  2653. -	bool result = false;
  2654. -
  2655. -	if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION")
  2656. -	||  SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id)
  2657. -	||  SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id) )
  2658. -		Sql_ShowDebug(sql_handle);
  2659. -	else
  2660. -		result = true;
  2661. -
  2662. -	result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") );
  2663. -
  2664. -	return result;
  2665. -}
  2666. -
  2667. -/// update an existing account with the provided new data (both account and regs)
  2668. -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc)
  2669. -{
  2670. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2671. -	return mmo_auth_tosql(db, acc, false);
  2672. -}
  2673. -
  2674. -/// retrieve data from db and store it in the provided data structure
  2675. -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id)
  2676. -{
  2677. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2678. -	return mmo_auth_fromsql(db, acc, account_id);
  2679. -}
  2680. -
  2681. -/// retrieve data from db and store it in the provided data structure
  2682. -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid)
  2683. -{
  2684. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2685. -	Sql* sql_handle = db->accounts;
  2686. -	char esc_userid[2*NAME_LENGTH+1];
  2687. -	int account_id;
  2688. -	char* data;
  2689. -
  2690. -	Sql_EscapeString(sql_handle, esc_userid, userid);
  2691. -
  2692. -	// get the list of account IDs for this user ID
  2693. -	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'",
  2694. -		db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid) )
  2695. -	{
  2696. -		Sql_ShowDebug(sql_handle);
  2697. -		return false;
  2698. -	}
  2699. -
  2700. -	if( Sql_NumRows(sql_handle) > 1 )
  2701. -	{// serious problem - duplicit account
  2702. -		ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid);
  2703. -		Sql_FreeResult(sql_handle);
  2704. -		return false;
  2705. -	}
  2706. -
  2707. -	if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  2708. -	{// no such entry
  2709. -		Sql_FreeResult(sql_handle);
  2710. -		return false;
  2711. -	}
  2712. -
  2713. -	Sql_GetData(sql_handle, 0, &data, NULL);
  2714. -	account_id = atoi(data);
  2715. -
  2716. -	return account_db_sql_load_num(self, acc, account_id);
  2717. -}
  2718. -
  2719. -
  2720. -/// Returns a new forward iterator.
  2721. -static AccountDBIterator* account_db_sql_iterator(AccountDB* self)
  2722. -{
  2723. -	AccountDB_SQL* db = (AccountDB_SQL*)self;
  2724. -	AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)aCalloc(1, sizeof(AccountDBIterator_SQL));
  2725. -
  2726. -	// set up the vtable
  2727. -	iter->vtable.destroy = &account_db_sql_iter_destroy;
  2728. -	iter->vtable.next    = &account_db_sql_iter_next;
  2729. -
  2730. -	// fill data
  2731. -	iter->db = db;
  2732. -	iter->last_account_id = -1;
  2733. -
  2734. -	return &iter->vtable;
  2735. -}
  2736. -
  2737. -
  2738. -/// Destroys this iterator, releasing all allocated memory (including itself).
  2739. -static void account_db_sql_iter_destroy(AccountDBIterator* self)
  2740. -{
  2741. -	AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self;
  2742. -	aFree(iter);
  2743. -}
  2744. -
  2745. -
  2746. -/// Fetches the next account in the database.
  2747. -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc)
  2748. -{
  2749. -	AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self;
  2750. -	AccountDB_SQL* db = (AccountDB_SQL*)iter->db;
  2751. -	Sql* sql_handle = db->accounts;
  2752. -	char* data;
  2753. -
  2754. -	// get next account ID
  2755. -	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1",
  2756. -		db->account_db, iter->last_account_id) )
  2757. -	{
  2758. -		Sql_ShowDebug(sql_handle);
  2759. -		return false;
  2760. -	}
  2761. -
  2762. -	if( SQL_SUCCESS == Sql_NextRow(sql_handle) &&
  2763. -		SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) &&
  2764. -		data != NULL )
  2765. -	{// get account data
  2766. -		int account_id;
  2767. -		account_id = atoi(data);
  2768. -		if( mmo_auth_fromsql(db, acc, account_id) )
  2769. -		{
  2770. -			iter->last_account_id = account_id;
  2771. -			Sql_FreeResult(sql_handle);
  2772. -			return true;
  2773. -		}
  2774. -	}
  2775. -	Sql_FreeResult(sql_handle);
  2776. -	return false;
  2777. -}
  2778. -
  2779. -
  2780. -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id)
  2781. -{
  2782. -	Sql* sql_handle = db->accounts;
  2783. -	char* data;
  2784. -	int i = 0;
  2785. -
  2786. -	// retrieve login entry for the specified account
  2787. -	if( SQL_ERROR == Sql_Query(sql_handle,
  2788. -	    "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change` FROM `%s` WHERE `account_id` = %d",
  2789. -		db->account_db, account_id )
  2790. -	) {
  2791. -		Sql_ShowDebug(sql_handle);
  2792. -		return false;
  2793. -	}
  2794. -
  2795. -	if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  2796. -	{// no such entry
  2797. -		Sql_FreeResult(sql_handle);
  2798. -		return false;
  2799. -	}
  2800. -
  2801. -	Sql_GetData(sql_handle,  0, &data, NULL); acc->account_id = atoi(data);
  2802. -	Sql_GetData(sql_handle,  1, &data, NULL); safestrncpy(acc->userid, data, sizeof(acc->userid));
  2803. -	Sql_GetData(sql_handle,  2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass));
  2804. -	Sql_GetData(sql_handle,  3, &data, NULL); acc->sex = data[0];
  2805. -	Sql_GetData(sql_handle,  4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email));
  2806. -	Sql_GetData(sql_handle,  5, &data, NULL); acc->group_id = atoi(data);
  2807. -	Sql_GetData(sql_handle,  6, &data, NULL); acc->state = strtoul(data, NULL, 10);
  2808. -	Sql_GetData(sql_handle,  7, &data, NULL); acc->unban_time = atol(data);
  2809. -	Sql_GetData(sql_handle,  8, &data, NULL); acc->expiration_time = atol(data);
  2810. -	Sql_GetData(sql_handle,  9, &data, NULL); acc->logincount = strtoul(data, NULL, 10);
  2811. -	Sql_GetData(sql_handle, 10, &data, NULL); safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin));
  2812. -	Sql_GetData(sql_handle, 11, &data, NULL); safestrncpy(acc->last_ip, data, sizeof(acc->last_ip));
  2813. -	Sql_GetData(sql_handle, 12, &data, NULL); safestrncpy(acc->birthdate, data, sizeof(acc->birthdate));
  2814. -	Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = atoi(data);
  2815. -	Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode));
  2816. -	Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data);
  2817. -
  2818. -	Sql_FreeResult(sql_handle);
  2819. -
  2820. -
  2821. -	// retrieve account regs for the specified user
  2822. -	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
  2823. -	{
  2824. -		Sql_ShowDebug(sql_handle);
  2825. -		return false;
  2826. -	}
  2827. -
  2828. -	acc->account_reg2_num = (int)Sql_NumRows(sql_handle);
  2829. -
  2830. -	while( SQL_SUCCESS == Sql_NextRow(sql_handle) )
  2831. -	{
  2832. -		char* data;
  2833. -		Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str));
  2834. -		Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value));
  2835. -		++i;
  2836. -	}
  2837. -	Sql_FreeResult(sql_handle);
  2838. -
  2839. -	if( i != acc->account_reg2_num )
  2840. -		return false;
  2841. -
  2842. -	return true;
  2843. -}
  2844. -
  2845. -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new)
  2846. -{
  2847. -	Sql* sql_handle = db->accounts;
  2848. -	SqlStmt* stmt = SqlStmt_Malloc(sql_handle);
  2849. -	bool result = false;
  2850. -	int i;
  2851. -
  2852. -	// try
  2853. -	do
  2854. -	{
  2855. -
  2856. -	if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") )
  2857. -	{
  2858. -		Sql_ShowDebug(sql_handle);
  2859. -		break;
  2860. -	}
  2861. -
  2862. -	if( is_new )
  2863. -	{// insert into account table
  2864. -		if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
  2865. -			"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
  2866. -			db->account_db)
  2867. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_INT,    (void*)&acc->account_id,      sizeof(acc->account_id))
  2868. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING, (void*)acc->userid,           strlen(acc->userid))
  2869. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_STRING, (void*)acc->pass,             strlen(acc->pass))
  2870. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  3, SQLDT_ENUM,   (void*)&acc->sex,             sizeof(acc->sex))
  2871. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  4, SQLDT_STRING, (void*)&acc->email,           strlen(acc->email))
  2872. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  5, SQLDT_INT,    (void*)&acc->group_id,        sizeof(acc->group_id))
  2873. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  6, SQLDT_UINT,   (void*)&acc->state,           sizeof(acc->state))
  2874. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  7, SQLDT_LONG,   (void*)&acc->unban_time,      sizeof(acc->unban_time))
  2875. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  8, SQLDT_INT,    (void*)&acc->expiration_time, sizeof(acc->expiration_time))
  2876. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  9, SQLDT_UINT,   (void*)&acc->logincount,      sizeof(acc->logincount))
  2877. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin,       strlen(acc->lastlogin))
  2878. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip,         strlen(acc->last_ip))
  2879. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate,       strlen(acc->birthdate))
  2880. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_UCHAR,  (void*)&acc->char_slots,      sizeof(acc->char_slots))
  2881. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING, (void*)&acc->pincode,         strlen(acc->pincode))
  2882. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG,   (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
  2883. -		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
  2884. -		) {
  2885. -			SqlStmt_ShowDebug(stmt);
  2886. -			break;
  2887. -		}
  2888. -	}
  2889. -	else
  2890. -	{// update account table
  2891. -		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id)
  2892. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_STRING, (void*)acc->userid,           strlen(acc->userid))
  2893. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_STRING, (void*)acc->pass,             strlen(acc->pass))
  2894. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  2, SQLDT_ENUM,   (void*)&acc->sex,             sizeof(acc->sex))
  2895. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  3, SQLDT_STRING, (void*)acc->email,            strlen(acc->email))
  2896. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  4, SQLDT_INT,    (void*)&acc->group_id,        sizeof(acc->group_id))
  2897. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  5, SQLDT_UINT,   (void*)&acc->state,           sizeof(acc->state))
  2898. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  6, SQLDT_LONG,   (void*)&acc->unban_time,      sizeof(acc->unban_time))
  2899. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  7, SQLDT_LONG,   (void*)&acc->expiration_time, sizeof(acc->expiration_time))
  2900. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  8, SQLDT_UINT,   (void*)&acc->logincount,      sizeof(acc->logincount))
  2901. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt,  9, SQLDT_STRING, (void*)&acc->lastlogin,       strlen(acc->lastlogin))
  2902. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip,         strlen(acc->last_ip))
  2903. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate,       strlen(acc->birthdate))
  2904. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_UCHAR,  (void*)&acc->char_slots,      sizeof(acc->char_slots))
  2905. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING, (void*)&acc->pincode,         strlen(acc->pincode))
  2906. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG,   (void*)&acc->pincode_change,  sizeof(acc->pincode_change))
  2907. -		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
  2908. -		) {
  2909. -			SqlStmt_ShowDebug(stmt);
  2910. -			break;
  2911. -		}
  2912. -	}
  2913. -
  2914. -	// remove old account regs
  2915. -	if( SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
  2916. -	{
  2917. -		Sql_ShowDebug(sql_handle);
  2918. -		break;
  2919. -	}
  2920. -	// insert new account regs
  2921. -	if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );",  db->accreg_db, acc->account_id) )
  2922. -	{
  2923. -		SqlStmt_ShowDebug(stmt);
  2924. -		break;
  2925. -	}
  2926. -	for( i = 0; i < acc->account_reg2_num; ++i )
  2927. -	{
  2928. -		if( SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str))
  2929. -		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value))
  2930. -		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
  2931. -		) {
  2932. -			SqlStmt_ShowDebug(stmt);
  2933. -			break;
  2934. -		}
  2935. -	}
  2936. -	if( i < acc->account_reg2_num )
  2937. -	{
  2938. -		result = false;
  2939. -		break;
  2940. -	}
  2941. -
  2942. -	// if we got this far, everything was successful
  2943. -	result = true;
  2944. -
  2945. -	} while(0);
  2946. -	// finally
  2947. -
  2948. -	result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") );
  2949. -	SqlStmt_Free(stmt);
  2950. -
  2951. -	return result;
  2952. -}
  2953. Index: src/login/login.h
  2954. ===================================================================
  2955. --- src/login/login.h	(revision 17365)
  2956. +++ src/login/login.h	(working copy)
  2957. @@ -6,6 +6,7 @@
  2958.  
  2959.  #include "../common/mmo.h" // NAME_LENGTH,SEX_*
  2960.  #include "../common/core.h" // CORE_ST_LAST
  2961. +#include "account.h"
  2962.  
  2963.  enum E_LOGINSERVER_ST
  2964.  {
  2965. @@ -40,8 +41,8 @@
  2966.  	int fd;
  2967.  };
  2968.  
  2969. +#define MAX_SERVERS 30
  2970.  struct mmo_char_server {
  2971. -
  2972.  	char name[20];
  2973.  	int fd;
  2974.  	uint32 ip;
  2975. @@ -49,7 +50,7 @@
  2976.  	uint16 users;       // user count on this server
  2977.  	uint16 type;        // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P
  2978.  	uint16 new_;        // should display as 'new'?
  2979. -};
  2980. +} server[MAX_SERVERS]; // char server data
  2981.  
  2982.  struct client_hash_node {
  2983.  	int group_id;
  2984. @@ -83,10 +84,15 @@
  2985.  	char dnsbl_servs[1024];                         // comma-separated list of dnsbl servers
  2986.  
  2987.  	char account_engine[256];                       // name of the engine to use (defaults to auto, for the first available engine)
  2988. +	int allowed_regs;				//max number of registration
  2989. +	int time_allowed;				//registration intervall in seconds
  2990.  
  2991.  	int client_hash_check;							// flags for checking client md5
  2992.  	struct client_hash_node *client_hash_nodes;		// linked list containg md5 hash for each gm group
  2993. -};
  2994. +	char *loginconf_name;
  2995. +	char *msgconf_name;
  2996. +	char *lanconf_name;
  2997. +} login_config;
  2998.  
  2999.  #define sex_num2str(num) ( (num ==  SEX_FEMALE  ) ? 'F' : (num ==  SEX_MALE  ) ? 'M' : 'S' )
  3000.  #define sex_str2num(str) ( (str == 'F' ) ?  SEX_FEMALE  : (str == 'M' ) ?  SEX_MALE  :  SEX_SERVER  )
  3001. @@ -94,15 +100,51 @@
  3002.  #define msg_config_read(cfgName) login_msg_config_read(cfgName)
  3003.  #define msg_txt(msg_number) login_msg_txt(msg_number)
  3004.  #define do_final_msg() login_do_final_msg()
  3005. -
  3006.  int login_msg_config_read(char *cfgName);
  3007.  const char* login_msg_txt(int msg_number);
  3008.  void login_do_final_msg(void);
  3009.  
  3010. +//-----------------------------------------------------
  3011. +// Online User Database [Wizputer]
  3012. +//-----------------------------------------------------
  3013. +struct online_login_data {
  3014. +	int account_id;
  3015. +	int waiting_disconnect;
  3016. +	int char_server;
  3017. +};
  3018. +DBMap* online_db; // int account_id -> struct online_login_data*
  3019.  
  3020. -#define MAX_SERVERS 30
  3021. -extern struct mmo_char_server server[MAX_SERVERS];
  3022. -extern struct Login_Config login_config;
  3023. +//-----------------------------------------------------
  3024. +// Auth database
  3025. +//-----------------------------------------------------
  3026. +#define AUTH_TIMEOUT 30000
  3027. +struct auth_node {
  3028. +	int account_id;
  3029. +	uint32 login_id1;
  3030. +	uint32 login_id2;
  3031. +	uint32 ip;
  3032. +	char sex;
  3033. +	uint32 version;
  3034. +	uint8 clienttype;
  3035. +};
  3036. +DBMap* auth_db; // int account_id -> struct auth_node*
  3037.  
  3038.  
  3039. +AccountDB* login_get_accounts_db(void);
  3040. +
  3041. +
  3042. +bool check_encrypted(const char* str1, const char* str2, const char* passwd);
  3043. +bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass);
  3044. +
  3045. +int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data);
  3046. +void remove_online_user(int account_id);
  3047. +struct online_login_data* add_online_user(int char_server, int account_id);
  3048. +int lan_subnetcheck(uint32 ip);
  3049. +
  3050. +int online_db_setoffline(DBKey key, DBData *data, va_list ap);
  3051. +DBData create_online_user(DBKey key, va_list args);
  3052. +
  3053. +int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip);
  3054. +int mmo_auth(struct login_session_data* sd, bool isServer);
  3055. +
  3056.  #endif /* _LOGIN_H_ */
  3057. Index: src/login/sql/CMakeLists.txt
  3058. ===================================================================
  3059. --- src/login/sql/CMakeLists.txt	(revision 17365)
  3060. +++ src/login/sql/CMakeLists.txt	(working copy)
  3061. @@ -8,13 +8,19 @@
  3062.  	"${SQL_LOGIN_SOURCE_DIR}/account.h"
  3063.  	"${SQL_LOGIN_SOURCE_DIR}/ipban.h"
  3064.  	"${SQL_LOGIN_SOURCE_DIR}/login.h"
  3065. +	"${SQL_LOGIN_SOURCE_DIR}/loginclif.h"
  3066. +	"${SQL_LOGIN_SOURCE_DIR}/loginchrif.h"
  3067. +	"${SQL_LOGIN_SOURCE_DIR}/logincnslif.h"
  3068.  	"${SQL_LOGIN_SOURCE_DIR}/loginlog.h"
  3069.  	)
  3070.  set( SQL_LOGIN_SOURCES
  3071. -	"${SQL_LOGIN_SOURCE_DIR}/account_sql.c"
  3072. -	"${SQL_LOGIN_SOURCE_DIR}/ipban_sql.c"
  3073. +	"${SQL_LOGIN_SOURCE_DIR}/account.c"
  3074. +	"${SQL_LOGIN_SOURCE_DIR}/ipban.c"
  3075.  	"${SQL_LOGIN_SOURCE_DIR}/login.c"
  3076. -	"${SQL_LOGIN_SOURCE_DIR}/loginlog_sql.c"
  3077. +	"${SQL_LOGIN_SOURCE_DIR}/loginclif.c"
  3078. +	"${SQL_LOGIN_SOURCE_DIR}/loginchrif.c"
  3079. +	"${SQL_LOGIN_SOURCE_DIR}/logincnslif.c"
  3080. +	"${SQL_LOGIN_SOURCE_DIR}/loginlog.c"
  3081.  	)
  3082.  set( DEPENDENCIES common_sql )
  3083.  set( LIBRARIES ${GLOBAL_LIBRARIES} )
  3084. Index: src/login/ipban.c
  3085. ===================================================================
  3086. --- src/login/ipban.c	(working copy)
  3087. +++ src/login/ipban.c	(working copy)
  3088. @@ -100,7 +100,7 @@
  3089.  	if( login_config.ipban_cleanup_interval > 0 )
  3090.  		// release data
  3091.  		delete_timer(cleanup_timer_id, ipban_cleanup);
  3092. -	
  3093. +
  3094.  	ipban_cleanup(0,0,0,0); // always clean up on login-server stop
  3095.  
  3096.  	// close connections
  3097. Index: src/login/Makefile.in
  3098. ===================================================================
  3099. --- src/login/Makefile.in	(revision 17365)
  3100. +++ src/login/Makefile.in	(working copy)
  3101. @@ -12,10 +12,9 @@
  3102.  	../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
  3103.  LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
  3104.  
  3105. -LOGIN_OBJ = login.o
  3106. -LOGIN_SQL_OBJ = $(LOGIN_OBJ:%=obj_sql/%) \
  3107. -	obj_sql/account_sql.o obj_sql/ipban_sql.o obj_sql/loginlog_sql.o
  3108. -LOGIN_H = login.h account.h ipban.h loginlog.h
  3109. +LOGIN_OBJ = login.o loginclif.o loginchrif.o logincnslif.o account.o ipban.o loginlog.o
  3110. +LOGIN_H = login.h loginclif.h loginchrif.h logincnslif.h account.h ipban.h loginlog.h
  3111. +LOGIN_SQL_OBJ = $(LOGIN_OBJ:%=obj_sql/%)
  3112.  
  3113.  HAVE_MYSQL=@HAVE_MYSQL@
  3114.  ifeq ($(HAVE_MYSQL),yes)
  3115. @@ -62,8 +61,8 @@
  3116.  login-server_sql: obj_sql $(LOGIN_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a  $(MT19937AR_OBJ)
  3117.  	@echo "	LD	$@"
  3118.  	@@CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@
  3119. -	    
  3120.  
  3121. +
  3122.  # login object files
  3123.  
  3124.  obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
  3125. Index: src/map/chrif.c
  3126. ===================================================================
  3127. --- src/map/chrif.c	(revision 17365)
  3128. +++ src/map/chrif.c	(working copy)
  3129. @@ -722,13 +722,14 @@
  3130.  
  3131.  	chrif_check(-1);
  3132.  
  3133. -	WFIFOHEAD(char_fd,18);
  3134. +	WFIFOHEAD(char_fd,19);
  3135.  	WFIFOW(char_fd, 0) = 0x2b02;
  3136.  	WFIFOL(char_fd, 2) = sd->bl.id;
  3137.  	WFIFOL(char_fd, 6) = sd->login_id1;
  3138.  	WFIFOL(char_fd,10) = sd->login_id2;
  3139.  	WFIFOL(char_fd,14) = htonl(s_ip);
  3140. -	WFIFOSET(char_fd,18);
  3141. +	WFIFOB(char_fd,18) = sd->version;
  3142. +	WFIFOSET(char_fd,19);
  3143.  
  3144.  	return 0;
  3145.  }
  3146. Index: src/map/pc.h
  3147. ===================================================================
  3148. --- src/map/pc.h	(revision 17365)
  3149. +++ src/map/pc.h	(working copy)
  3150. @@ -185,6 +185,7 @@
  3151.  		unsigned int bonus_coma : 1;
  3152.  	} special_state;
  3153.  	int login_id1, login_id2;
  3154. +	int version;
  3155.  	unsigned short class_;	//This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex]
  3156.  	int group_id, group_pos, group_level;
  3157.  	unsigned int permissions;/* group permissions */
  3158. Index: src/char/char.c
  3159. ===================================================================
  3160. --- src/char/char.c	(revision 17365)
  3161. +++ src/char/char.c	(working copy)
  3162. @@ -33,10 +33,9 @@
  3163.  #include <stdlib.h>
  3164.  #include <malloc.h>
  3165.  
  3166. -#define MAX_STARTITEM 32
  3167. -#define CHAR_MAX_MSG 300
  3168. -static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
  3169. -
  3170. +// <editor-fold defaultstate="collapsed" desc="db_tablename">
  3171. +int db_use_sqldbs;
  3172. +char db_path[1024] = "db";
  3173.  char char_db[256] = "char";
  3174.  char scdata_db[256] = "sc_data";
  3175.  char cart_db[256] = "cart_inventory";
  3176. @@ -67,16 +66,17 @@
  3177.  char mercenary_db[256] = "mercenary";
  3178.  char mercenary_owner_db[256] = "mercenary_owner";
  3179.  char ragsrvinfo_db[256] = "ragsrvinfo";
  3180. +// </editor-fold>
  3181.  
  3182. +
  3183.  // show loading/saving messages
  3184.  int save_log = 1;
  3185.  
  3186.  static DBMap* char_db_; // int char_id -> struct mmo_charstatus*
  3187.  
  3188. -char db_path[1024] = "db";
  3189. +#define CHAR_MAX_MSG 300
  3190. +static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
  3191.  
  3192. -int db_use_sqldbs;
  3193. -
  3194.  struct mmo_map_server {
  3195.  	int fd;
  3196.  	uint32 ip;
  3197. @@ -115,103 +115,90 @@
  3198.  int log_char = 1;	// loggin char or not [devil]
  3199.  int log_inter = 1;	// loggin inter or not [devil]
  3200.  
  3201. -// Advanced subnet check [LuzZza]
  3202. -struct s_subnet {
  3203. -	uint32 mask;
  3204. -	uint32 char_ip;
  3205. -	uint32 map_ip;
  3206. -} subnet[16];
  3207. -int subnet_count = 0;
  3208. +// check for exit signal
  3209. +// 0 is saving complete
  3210. +// other is char_id
  3211. +unsigned int save_flag = 0;
  3212. +// Initial position (it's possible to set it in conf file)
  3213. +struct point start_point = { 0, 53, 111 };
  3214. +int console = 0;
  3215. +int max_connect_user = -1;
  3216. +int gm_allow_group = -1;
  3217. +int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  3218. +int start_zeny = 0;
  3219. +int guild_exp_rate = 100;
  3220.  
  3221. -struct char_session_data {
  3222. -	bool auth; // whether the session is authed or not
  3223. -	int account_id, login_id1, login_id2, sex;
  3224. -	int found_char[MAX_CHARS]; // ids of chars on this account
  3225. -	char email[40]; // e-mail (default: [email protected]) by [Yor]
  3226. -	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  3227. -	int group_id; // permission
  3228. -	uint8 char_slots;
  3229. -	uint32 version;
  3230. -	uint8 clienttype;
  3231. -	char new_name[NAME_LENGTH];
  3232. -	char birthdate[10+1];  // YYYY-MM-DD
  3233. -	// Pincode system
  3234. -	char pincode[PINCODE_LENGTH+1];
  3235. -	uint32 pincode_seed;
  3236. -	time_t pincode_change;
  3237. -	uint16 pincode_try;
  3238. -	// Addon system
  3239. -	unsigned int char_moves[MAX_CHARS]; // character moves left
  3240. -};
  3241. -
  3242. +#define MAX_STARTITEM 32
  3243.  struct startitem {
  3244.  	int nameid; //Item ID
  3245.  	int amount; //Number of items
  3246.  	int pos; //Position (for auto-equip)
  3247.  } start_items[MAX_STARTITEM+1];
  3248.  
  3249. -int max_connect_user = -1;
  3250. -int gm_allow_group = -1;
  3251. -int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  3252. -int start_zeny = 0;
  3253. -int guild_exp_rate = 100;
  3254. -
  3255.  // Pincode system
  3256. -#define PINCODE_OK 0
  3257. -#define PINCODE_ASK 1
  3258. -#define PINCODE_NOTSET 2
  3259. -#define PINCODE_EXPIRED 3
  3260. -#define PINCODE_NEW 4
  3261. -#define PINCODE_PASSED 7
  3262. -#define	PINCODE_WRONG 8
  3263. -
  3264. +enum pincode_state {
  3265. +	PINCODE_OK = 0,
  3266. +	PINCODE_ASK,
  3267. +	PINCODE_NOTSET,
  3268. +	PINCODE_EXPIRED,
  3269. +	PINCODE_NEW,
  3270. +	PINCODE_PASSED,
  3271. +	PINCODE_WRONG,
  3272. +	PINCODE_MAXSTATE
  3273. +};
  3274.  bool pincode_enabled = true;
  3275.  int pincode_changetime = 0;
  3276.  int pincode_maxtry = 3;
  3277.  bool pincode_force = true;
  3278.  
  3279. -void pincode_check( int fd, struct char_session_data* sd );
  3280. -void pincode_change( int fd, struct char_session_data* sd );
  3281. -void pincode_setnew( int fd, struct char_session_data* sd );
  3282. -void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state );
  3283. -void pincode_notifyLoginPinUpdate( int account_id, char* pin );
  3284. -void pincode_notifyLoginPinError( int account_id );
  3285. -void pincode_decrypt( uint32 userSeed, char* pin );
  3286. -int pincode_compare( int fd, struct char_session_data* sd, char* pin );
  3287. -
  3288.  // Addon system
  3289.  bool char_move_enabled = true;
  3290.  bool char_movetoused = true;
  3291.  bool char_moves_unlimited = false;
  3292.  
  3293. -void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to );
  3294. -void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason );
  3295. -
  3296.  //Custom limits for the fame lists. [Skotlex]
  3297.  int fame_list_size_chemist = MAX_FAME_LIST;
  3298.  int fame_list_size_smith = MAX_FAME_LIST;
  3299.  int fame_list_size_taekwon = MAX_FAME_LIST;
  3300. -
  3301.  // Char-server-side stored fame lists [DracoRPG]
  3302.  struct fame_list smith_fame_list[MAX_FAME_LIST];
  3303.  struct fame_list chemist_fame_list[MAX_FAME_LIST];
  3304.  struct fame_list taekwon_fame_list[MAX_FAME_LIST];
  3305.  
  3306. -// check for exit signal
  3307. -// 0 is saving complete
  3308. -// other is char_id
  3309. -unsigned int save_flag = 0;
  3310.  
  3311. -// Initial position (it's possible to set it in conf file)
  3312. -struct point start_point = { 0, 53, 111 };
  3313. +// Advanced subnet check [LuzZza]
  3314. +struct s_subnet {
  3315. +	uint32 mask;
  3316. +	uint32 char_ip;
  3317. +	uint32 map_ip;
  3318. +} subnet[16];
  3319. +int subnet_count = 0;
  3320.  
  3321. -int console = 0;
  3322. +struct char_session_data {
  3323. +	bool auth; // whether the session is authed or not
  3324. +	int account_id, login_id1, login_id2, sex;
  3325. +	int found_char[MAX_CHARS]; // ids of chars on this account
  3326. +	char email[40]; // e-mail (default: [email protected]) by [Yor]
  3327. +	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  3328. +	int group_id; // permission
  3329. +	uint8 char_slots;
  3330. +	uint32 version;
  3331. +	uint8 clienttype;
  3332. +	char new_name[NAME_LENGTH];
  3333. +	char birthdate[10+1];  // YYYY-MM-DD
  3334. +	// Pincode system
  3335. +	char pincode[PINCODE_LENGTH+1];
  3336. +	uint32 pincode_seed;
  3337. +	time_t pincode_change;
  3338. +	uint16 pincode_try;
  3339. +	// Addon system
  3340. +	unsigned int char_moves[MAX_CHARS]; // character moves left
  3341. +};
  3342.  
  3343.  //-----------------------------------------------------
  3344.  // Auth database
  3345.  //-----------------------------------------------------
  3346.  #define AUTH_TIMEOUT 30000
  3347. -
  3348.  struct auth_node {
  3349.  	int account_id;
  3350.  	int char_id;
  3351. @@ -223,13 +210,11 @@
  3352.  	int group_id;
  3353.  	unsigned changing_mapservers : 1;
  3354.  };
  3355. -
  3356.  static DBMap* auth_db; // int account_id -> struct auth_node*
  3357.  
  3358.  //-----------------------------------------------------
  3359.  // Online User Database
  3360.  //-----------------------------------------------------
  3361. -
  3362.  struct online_char_data {
  3363.  	int account_id;
  3364.  	int char_id;
  3365. @@ -237,9 +222,14 @@
  3366.  	int waiting_disconnect;
  3367.  	short server; // -2: unknown server, -1: not connected, 0+: id of server
  3368.  	bool pincode_success;
  3369. +	int version;
  3370.  };
  3371. +static DBMap* online_char_db; // int account_id -> struct online_char_data*
  3372.  
  3373. -static DBMap* online_char_db; // int account_id -> struct online_char_data*
  3374. +
  3375. +int parse_char(int fd);
  3376. +int parse_fromlogin(int fd);
  3377. +
  3378.  static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
  3379.  int delete_char_sql(int char_id);
  3380.  
  3381. @@ -1616,11 +1606,11 @@
  3382.  #else
  3383.  	//Insert the new char entry to the database
  3384.  	if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
  3385. -							   "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
  3386. -							   "'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
  3387. -							   char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk,
  3388. -							   (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
  3389. -							   mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) )
  3390. +		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
  3391. +		"'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
  3392. +		char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk,
  3393. +		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
  3394. +		mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) )
  3395.  	{
  3396.  		Sql_ShowDebug(sql_handle);
  3397.  		return -2; //No, stop the procedure!
  3398. @@ -1951,8 +1941,12 @@
  3399.  }
  3400.  
  3401.  //struct PACKET_CH_CHARLIST_REQ { 0x0 short PacketType}
  3402. -void char_parse_req_charlist(int fd, struct char_session_data* sd){
  3403. +int char_parse_req_charlist(int fd, struct char_session_data* sd){
  3404. +	if( RFIFOREST(fd) < 2 )
  3405. +		return 0;
  3406. +	RFIFOSKIP(fd,2);
  3407.  	mmo_char_send099d(fd,sd);
  3408. +	return 1;
  3409.  }
  3410.  
  3411.  //----------------------------------------
  3412. @@ -1960,7 +1954,8 @@
  3413.  //----------------------------------------
  3414.  int mmo_char_send006b(int fd, struct char_session_data* sd){
  3415.  	int j, offset = 0;
  3416. -	if(sd->version > 25) //20100413
  3417. +	bool newvers = (sd->version > date2version(20100413)); //because long check
  3418. +	if(newvers) //20100413
  3419.  		offset += 3;
  3420.  	if (save_log)
  3421.  		ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id);
  3422. @@ -1968,7 +1963,7 @@
  3423.  	j = 24 + offset; // offset
  3424.  	WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF);
  3425.  	WFIFOW(fd,0) = 0x6b;
  3426. -	if(sd->version > 25){ //20100413
  3427. +	if(newvers){ //20100413
  3428.  		WFIFOB(fd,4) = MAX_CHARS; // Max slots.
  3429.  		WFIFOB(fd,5) = sd->char_slots; // Available slots. (PremiumStartSlot)
  3430.  		WFIFOB(fd,6) = MAX_CHARS; // Premium slots. (Any existent chars past sd->char_slots but within MAX_CHARS will show a 'Premium Service' in red)
  3431. @@ -2001,13 +1996,12 @@
  3432.  
  3433.  void mmo_char_send(int fd, struct char_session_data* sd){
  3434.  	ShowInfo("sd->version = %d\n",sd->version);
  3435. -#if PACKETVER >= 20130000
  3436. +	if(sd->version > date2version(20130000)){
  3437.  		mmo_char_send082d(fd,sd);
  3438.  		char_charlist_notify(fd,sd);
  3439.  		char_block_character(fd,sd);
  3440. -#endif
  3441. -	//@FIXME dump from kro doesn't show 6b transmission
  3442. -	mmo_char_send006b(fd,sd);
  3443. +	}
  3444. +	mmo_char_send006b(fd,sd); //@FIXME dump from kro doesn't show 6b transmission
  3445.  }
  3446.  
  3447.  int char_married(int pl1, int pl2)
  3448. @@ -2089,6 +2083,21 @@
  3449.  		set_eof(i);
  3450.  }
  3451.  
  3452. +/*
  3453. + * Transmit auth result to client
  3454. + * <result>.B ()
  3455. + * result :
  3456. + *  1 : Server closed
  3457. + *  2 : Someone has already logged in with this id
  3458. + *  8 : already online
  3459. + */
  3460. +void char_send_auth_result(int fd,char result){
  3461. +	WFIFOHEAD(fd,3);
  3462. +	WFIFOW(fd,0) = 0x81;
  3463. +	WFIFOB(fd,2) = result;
  3464. +	WFIFOSET(fd,3);
  3465. +}
  3466. +
  3467.  static void char_auth_ok(int fd, struct char_session_data *sd)
  3468.  {
  3469.  	struct online_char_data* character;
  3470. @@ -2100,18 +2109,12 @@
  3471.  			mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  3472.  			if (character->waiting_disconnect == INVALID_TIMER)
  3473.  				character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0);
  3474. -			WFIFOHEAD(fd,3);
  3475. -			WFIFOW(fd,0) = 0x81;
  3476. -			WFIFOB(fd,2) = 8;
  3477. -			WFIFOSET(fd,3);
  3478. +			char_send_auth_result(fd,8);
  3479.  			return;
  3480.  		}
  3481.  		if (character->fd >= 0 && character->fd != fd)
  3482.  		{	//There's already a connection from this account that hasn't picked a char yet.
  3483. -			WFIFOHEAD(fd,3);
  3484. -			WFIFOW(fd,0) = 0x81;
  3485. -			WFIFOB(fd,2) = 8;
  3486. -			WFIFOSET(fd,3);
  3487. +			char_send_auth_result(fd,8);
  3488.  			return;
  3489.  		}
  3490.  		character->fd = fd;
  3491. @@ -2184,369 +2187,6 @@
  3492.  		ShowStatus("Awaiting maps from map-server.\n");
  3493.  }
  3494.  
  3495. -
  3496. -int parse_fromlogin(int fd) {
  3497. -	struct char_session_data* sd = NULL;
  3498. -	int i;
  3499. -
  3500. -	// only process data from the login-server
  3501. -	if( fd != login_fd ) {
  3502. -		ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
  3503. -		do_close(fd);
  3504. -		return 0;
  3505. -	}
  3506. -
  3507. -	if( session[fd]->flag.eof ) {
  3508. -		do_close(fd);
  3509. -		login_fd = -1;
  3510. -		loginif_on_disconnect();
  3511. -		return 0;
  3512. -	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
  3513. -		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
  3514. -			set_eof(fd);
  3515. -			return 0;
  3516. -		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
  3517. -			WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
  3518. -			WFIFOW(fd,0) = 0x2719;
  3519. -			WFIFOSET(fd,2);
  3520. -
  3521. -			session[fd]->flag.ping = 2;
  3522. -		}
  3523. -	}
  3524. -
  3525. -	sd = (struct char_session_data*)session[fd]->session_data;
  3526. -
  3527. -	while(RFIFOREST(fd) >= 2) {
  3528. -		uint16 command = RFIFOW(fd,0);
  3529. -
  3530. -		switch( command )
  3531. -		{
  3532. -
  3533. -		// acknowledgement of connect-to-loginserver request
  3534. -		case 0x2711:
  3535. -			if (RFIFOREST(fd) < 3)
  3536. -				return 0;
  3537. -
  3538. -			if (RFIFOB(fd,2)) {
  3539. -				//printf("connect login server error : %d\n", RFIFOB(fd,2));
  3540. -				ShowError("Can not connect to login-server.\n");
  3541. -				ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  3542. -				ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
  3543. -				ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
  3544. -				set_eof(fd);
  3545. -				return 0;
  3546. -			} else {
  3547. -				ShowStatus("Connected to login-server (connection #%d).\n", fd);
  3548. -				loginif_on_ready();
  3549. -			}
  3550. -			RFIFOSKIP(fd,3);
  3551. -		break;
  3552. -
  3553. -		// acknowledgement of account authentication request
  3554. -		case 0x2713:
  3555. -			if (RFIFOREST(fd) < 25)
  3556. -				return 0;
  3557. -		{
  3558. -			int account_id = RFIFOL(fd,2);
  3559. -			uint32 login_id1 = RFIFOL(fd,6);
  3560. -			uint32 login_id2 = RFIFOL(fd,10);
  3561. -			uint8 sex = RFIFOB(fd,14);
  3562. -			uint8 result = RFIFOB(fd,15);
  3563. -			int request_id = RFIFOL(fd,16);
  3564. -			uint32 version = RFIFOL(fd,20);
  3565. -			uint8 clienttype = RFIFOB(fd,24);
  3566. -			RFIFOSKIP(fd,25);
  3567. -
  3568. -			if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
  3569. -				!sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
  3570. -			{
  3571. -				int client_fd = request_id;
  3572. -				sd->version = version;
  3573. -				sd->clienttype = clienttype;
  3574. -				switch( result )
  3575. -				{
  3576. -				case 0:// ok
  3577. -					char_auth_ok(client_fd, sd);
  3578. -					break;
  3579. -				case 1:// auth failed
  3580. -					WFIFOHEAD(client_fd,3);
  3581. -					WFIFOW(client_fd,0) = 0x6c;
  3582. -					WFIFOB(client_fd,2) = 0;// rejected from server
  3583. -					WFIFOSET(client_fd,3);
  3584. -					break;
  3585. -				}
  3586. -			}
  3587. -		}
  3588. -		break;
  3589. -
  3590. -		case 0x2717: // account data
  3591. -			if (RFIFOREST(fd) < 72)
  3592. -				return 0;
  3593. -
  3594. -			// find the authenticated session with this account id
  3595. -			ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) );
  3596. -			if( i < fd_max )
  3597. -			{
  3598. -				int server_id;
  3599. -				memcpy(sd->email, RFIFOP(fd,6), 40);
  3600. -				sd->expiration_time = (time_t)RFIFOL(fd,46);
  3601. -				sd->group_id = RFIFOB(fd,50);
  3602. -				sd->char_slots = RFIFOB(fd,51);
  3603. -				if( sd->char_slots > MAX_CHARS ) {
  3604. -					ShowError("Account '%d' `character_slots` column is higher than supported MAX_CHARS (%d), update MAX_CHARS in mmo.h! capping to MAX_CHARS...\n",sd->account_id,sd->char_slots);
  3605. -					sd->char_slots = MAX_CHARS;/* cap to maximum */
  3606. -				} else if ( !sd->char_slots )/* no value aka 0 in sql */
  3607. -					sd->char_slots = MAX_CHARS;/* cap to maximum */
  3608. -				safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
  3609. -				safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
  3610. -				sd->pincode_change = (time_t)RFIFOL(fd,68);
  3611. -				ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
  3612. -				// continued from char_auth_ok...
  3613. -				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
  3614. -					(max_connect_user == 0 && sd->group_id != gm_allow_group) ||
  3615. -					( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
  3616. -					// refuse connection (over populated)
  3617. -					WFIFOHEAD(i,3);
  3618. -					WFIFOW(i,0) = 0x6c;
  3619. -					WFIFOW(i,2) = 0;
  3620. -					WFIFOSET(i,3);
  3621. -				} else {
  3622. -					// send characters to player
  3623. -					mmo_char_send(i, sd);
  3624. -#if PACKETVER >=  20110309
  3625. -					if( pincode_enabled ){
  3626. -						// PIN code system enabled
  3627. -						if( strlen( sd->pincode ) <= 0 ){
  3628. -							// No PIN code has been set yet
  3629. -							if( pincode_force ){
  3630. -								pincode_sendstate( i, sd, PINCODE_NEW );
  3631. -							}else{
  3632. -								pincode_sendstate( i, sd, PINCODE_PASSED );
  3633. -							}
  3634. -						}else{
  3635. -							if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
  3636. -								struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
  3637. -
  3638. -								if( node != NULL && node->pincode_success ){
  3639. -									// User has already passed the check
  3640. -									pincode_sendstate( i, sd, PINCODE_PASSED );
  3641. -								}else{
  3642. -									// Ask user for his PIN code
  3643. -									pincode_sendstate( i, sd, PINCODE_ASK );
  3644. -								}
  3645. -							}else{
  3646. -								// User hasnt changed his PIN code too long
  3647. -								pincode_sendstate( i, sd, PINCODE_EXPIRED );
  3648. -							}
  3649. -						}
  3650. -					}else{
  3651. -						// PIN code system disabled
  3652. -						pincode_sendstate( i, sd, PINCODE_OK );
  3653. -					}
  3654. -#endif
  3655. -				}
  3656. -			}
  3657. -			RFIFOSKIP(fd,72);
  3658. -		break;
  3659. -
  3660. -		// login-server alive packet
  3661. -		case 0x2718:
  3662. -			if (RFIFOREST(fd) < 2)
  3663. -				return 0;
  3664. -			RFIFOSKIP(fd,2);
  3665. -			session[fd]->flag.ping = 0;
  3666. -		break;
  3667. -
  3668. -		// changesex reply
  3669. -		case 0x2723:
  3670. -			if (RFIFOREST(fd) < 7)
  3671. -				return 0;
  3672. -		{
  3673. -			unsigned char buf[7];
  3674. -
  3675. -			int acc = RFIFOL(fd,2);
  3676. -			int sex = RFIFOB(fd,6);
  3677. -			RFIFOSKIP(fd,7);
  3678. -
  3679. -			if( acc > 0 )
  3680. -			{// TODO: Is this even possible?
  3681. -				int char_id[MAX_CHARS];
  3682. -				int class_[MAX_CHARS];
  3683. -				int guild_id[MAX_CHARS];
  3684. -				int num;
  3685. -				char* data;
  3686. -
  3687. -				struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
  3688. -				if( node != NULL )
  3689. -					node->sex = sex;
  3690. -
  3691. -				// get characters
  3692. -				if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
  3693. -					Sql_ShowDebug(sql_handle);
  3694. -				for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
  3695. -				{
  3696. -					Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
  3697. -					Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
  3698. -					Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
  3699. -				}
  3700. -				num = i;
  3701. -				for( i = 0; i < num; ++i )
  3702. -				{
  3703. -					if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
  3704. -						class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
  3705. -						class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
  3706. -						class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
  3707. -						class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
  3708. -						class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
  3709. -						class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  3710. -					{
  3711. -						// job modification
  3712. -						if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
  3713. -							class_[i] = (sex ? JOB_BARD : JOB_DANCER);
  3714. -						else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
  3715. -							class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
  3716. -						else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
  3717. -							class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
  3718. -						else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
  3719. -							class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
  3720. -						else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
  3721. -							class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
  3722. -						else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
  3723. -							class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
  3724. -						else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  3725. -							class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
  3726. -					}
  3727. -
  3728. -					if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) )
  3729. -						Sql_ShowDebug(sql_handle);
  3730. -
  3731. -					if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
  3732. -						inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
  3733. -				}
  3734. -				Sql_FreeResult(sql_handle);
  3735. -
  3736. -				// disconnect player if online on char-server
  3737. -				disconnect_player(acc);
  3738. -			}
  3739. -
  3740. -			// notify all mapservers about this change
  3741. -			WBUFW(buf,0) = 0x2b0d;
  3742. -			WBUFL(buf,2) = acc;
  3743. -			WBUFB(buf,6) = sex;
  3744. -			mapif_sendall(buf, 7);
  3745. -		}
  3746. -		break;
  3747. -
  3748. -		// reply to an account_reg2 registry request
  3749. -		case 0x2729:
  3750. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  3751. -				return 0;
  3752. -
  3753. -		{	//Receive account_reg2 registry, forward to map servers.
  3754. -			unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
  3755. -			memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  3756. -			WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  3757. -			mapif_sendall(buf, WBUFW(buf,2));
  3758. -			RFIFOSKIP(fd, RFIFOW(fd,2));
  3759. -		}
  3760. -		break;
  3761. -
  3762. -		// State change of account/ban notification (from login-server)
  3763. -		case 0x2731:
  3764. -			if (RFIFOREST(fd) < 11)
  3765. -				return 0;
  3766. -
  3767. -		{	// send to all map-servers to disconnect the player
  3768. -			unsigned char buf[11];
  3769. -			WBUFW(buf,0) = 0x2b14;
  3770. -			WBUFL(buf,2) = RFIFOL(fd,2);
  3771. -			WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  3772. -			WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  3773. -			mapif_sendall(buf, 11);
  3774. -		}
  3775. -			// disconnect player if online on char-server
  3776. -			disconnect_player(RFIFOL(fd,2));
  3777. -
  3778. -			RFIFOSKIP(fd,11);
  3779. -		break;
  3780. -
  3781. -		// Login server request to kick a character out. [Skotlex]
  3782. -		case 0x2734:
  3783. -			if (RFIFOREST(fd) < 6)
  3784. -				return 0;
  3785. -		{
  3786. -			int aid = RFIFOL(fd,2);
  3787. -			struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
  3788. -			RFIFOSKIP(fd,6);
  3789. -			if( character != NULL )
  3790. -			{// account is already marked as online!
  3791. -				if( character->server > -1 )
  3792. -				{	//Kick it from the map server it is on.
  3793. -					mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  3794. -					if (character->waiting_disconnect == INVALID_TIMER)
  3795. -						character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
  3796. -				}
  3797. -				else
  3798. -				{// Manual kick from char server.
  3799. -					struct char_session_data *tsd;
  3800. -					int i;
  3801. -					ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
  3802. -					if( i < fd_max )
  3803. -					{
  3804. -						WFIFOHEAD(i,3);
  3805. -						WFIFOW(i,0) = 0x81;
  3806. -						WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
  3807. -						WFIFOSET(i,3);
  3808. -						set_eof(i);
  3809. -					}
  3810. -					else // still moving to the map-server
  3811. -						set_char_offline(-1, aid);
  3812. -				}
  3813. -			}
  3814. -			idb_remove(auth_db, aid);// reject auth attempts from map-server
  3815. -		}
  3816. -		break;
  3817. -
  3818. -		// ip address update signal from login server
  3819. -		case 0x2735:
  3820. -		{
  3821. -			unsigned char buf[2];
  3822. -			uint32 new_ip = 0;
  3823. -
  3824. -			WBUFW(buf,0) = 0x2b1e;
  3825. -			mapif_sendall(buf, 2);
  3826. -
  3827. -			new_ip = host2ip(login_ip_str);
  3828. -			if (new_ip && new_ip != login_ip)
  3829. -				login_ip = new_ip; //Update login ip, too.
  3830. -
  3831. -			new_ip = host2ip(char_ip_str);
  3832. -			if (new_ip && new_ip != char_ip)
  3833. -			{	//Update ip.
  3834. -				char_ip = new_ip;
  3835. -				ShowInfo("Updating IP for [%s].\n", char_ip_str);
  3836. -				// notify login server about the change
  3837. -				WFIFOHEAD(fd,6);
  3838. -				WFIFOW(fd,0) = 0x2736;
  3839. -				WFIFOL(fd,2) = htonl(char_ip);
  3840. -				WFIFOSET(fd,6);
  3841. -			}
  3842. -
  3843. -			RFIFOSKIP(fd,2);
  3844. -		}
  3845. -		break;
  3846. -
  3847. -		default:
  3848. -			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
  3849. -			set_eof(fd);
  3850. -			return 0;
  3851. -		}
  3852. -	}
  3853. -
  3854. -	RFIFOFLUSH(fd);
  3855. -	return 0;
  3856. -}
  3857. -
  3858.  int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data);
  3859.  int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
  3860.  
  3861. @@ -2779,729 +2419,856 @@
  3862.  	mapif_server_reset(id);
  3863.  }
  3864.  
  3865. +void do_init_mapif(void)
  3866. +{
  3867. +	int i;
  3868. +	for( i = 0; i < ARRAYLENGTH(server); ++i )
  3869. +		mapif_server_init(i);
  3870. +}
  3871.  
  3872. -int parse_frommap(int fd)
  3873. +void do_final_mapif(void)
  3874.  {
  3875. +	int i;
  3876. +	for( i = 0; i < ARRAYLENGTH(server); ++i )
  3877. +		mapif_server_destroy(i);
  3878. +}
  3879. +
  3880. +// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
  3881. +// If found, returns the server's index in the 'server' array (otherwise returns -1).
  3882. +int search_mapserver(unsigned short map, uint32 ip, uint16 port)
  3883. +{
  3884.  	int i, j;
  3885. -	int id;
  3886.  
  3887. -	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  3888. -	if( id == ARRAYLENGTH(server) )
  3889. -	{// not a map server
  3890. -		ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
  3891. -		do_close(fd);
  3892. -		return 0;
  3893. +	for(i = 0; i < ARRAYLENGTH(server); i++)
  3894. +	{
  3895. +		if (server[i].fd > 0
  3896. +		&& (ip == (uint32)-1 || server[i].ip == ip)
  3897. +		&& (port == (uint16)-1 || server[i].port == port))
  3898. +		{
  3899. +			for (j = 0; server[i].map[j]; j++)
  3900. +				if (server[i].map[j] == map)
  3901. +					return i;
  3902. +		}
  3903.  	}
  3904. -	if( session[fd]->flag.eof )
  3905. -	{
  3906. -		do_close(fd);
  3907. -		server[id].fd = -1;
  3908. -		mapif_on_disconnect(id);
  3909. +
  3910. +	return -1;
  3911. +}
  3912. +
  3913. +// Initialization process (currently only initialization inter_mapif)
  3914. +static int char_mapif_init(int fd)
  3915. +{
  3916. +	return inter_mapif_init(fd);
  3917. +}
  3918. +
  3919. +//--------------------------------------------
  3920. +// Test to know if an IP come from LAN or WAN.
  3921. +//--------------------------------------------
  3922. +int lan_subnetcheck(uint32 ip)
  3923. +{
  3924. +	int i;
  3925. +	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  3926. +	if( i < subnet_count ) {
  3927. +		ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask));
  3928. +		return subnet[i].map_ip;
  3929. +	} else {
  3930. +		ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
  3931.  		return 0;
  3932.  	}
  3933. +}
  3934.  
  3935. -	while(RFIFOREST(fd) >= 2){
  3936. -		switch(RFIFOW(fd,0)){
  3937.  
  3938. -		case 0x2afa: // Receiving map names list from the map-server
  3939. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  3940. -				return 0;
  3941. +//For use in packets that depend on an sd being present [Skotlex]
  3942. +#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
  3943.  
  3944. -			memset(server[id].map, 0, sizeof(server[id].map));
  3945. -			j = 0;
  3946. -			for(i = 4; i < RFIFOW(fd,2); i += 4) {
  3947. -				server[id].map[j] = RFIFOW(fd,i);
  3948. -				j++;
  3949. -			}
  3950. +///
  3951. +/// Map IF
  3952. +///
  3953.  
  3954. -			ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  3955. -						id, j, CONVIP(server[id].ip), server[id].port);
  3956. -			ShowStatus("Map-server %d loading complete.\n", id);
  3957. +int char_parsemap_getmapname(int fd, int id){
  3958. +	int j = 0, i = 0;
  3959. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  3960. +		return 0;
  3961.  
  3962. -			// send name for wisp to player
  3963. -			WFIFOHEAD(fd, 3 + NAME_LENGTH);
  3964. -			WFIFOW(fd,0) = 0x2afb;
  3965. -			WFIFOB(fd,2) = 0;
  3966. -			memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
  3967. -			WFIFOSET(fd,3+NAME_LENGTH);
  3968. +	memset(server[id].map, 0, sizeof(server[id].map));
  3969. +	for(i = 4; i < RFIFOW(fd,2); i += 4) {
  3970. +		server[id].map[j] = RFIFOW(fd,i);
  3971. +		j++;
  3972. +	}
  3973.  
  3974. -			char_send_fame_list(fd); //Send fame list.
  3975. +	ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  3976. +				id, j, CONVIP(server[id].ip), server[id].port);
  3977. +	ShowStatus("Map-server %d loading complete.\n", id);
  3978.  
  3979. -			{
  3980. -			unsigned char buf[16384];
  3981. -			int x;
  3982. -			if (j == 0) {
  3983. -				ShowWarning("Map-server %d has NO maps.\n", id);
  3984. -			} else {
  3985. -				// Transmitting maps information to the other map-servers
  3986. -				WBUFW(buf,0) = 0x2b04;
  3987. -				WBUFW(buf,2) = j * 4 + 10;
  3988. -				WBUFL(buf,4) = htonl(server[id].ip);
  3989. -				WBUFW(buf,8) = htons(server[id].port);
  3990. -				memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
  3991. -				mapif_sendallwos(fd, buf, WBUFW(buf,2));
  3992. -			}
  3993. -			// Transmitting the maps of the other map-servers to the new map-server
  3994. -			for(x = 0; x < ARRAYLENGTH(server); x++) {
  3995. -				if (server[x].fd > 0 && x != id) {
  3996. -					WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
  3997. -					WFIFOW(fd,0) = 0x2b04;
  3998. -					WFIFOL(fd,4) = htonl(server[x].ip);
  3999. -					WFIFOW(fd,8) = htons(server[x].port);
  4000. -					j = 0;
  4001. -					for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
  4002. -						if (server[x].map[i])
  4003. -							WFIFOW(fd,10+(j++)*4) = server[x].map[i];
  4004. -					if (j > 0) {
  4005. -						WFIFOW(fd,2) = j * 4 + 10;
  4006. -						WFIFOSET(fd,WFIFOW(fd,2));
  4007. -					}
  4008. -				}
  4009. -			}
  4010. -			}
  4011. -			RFIFOSKIP(fd,RFIFOW(fd,2));
  4012. -		break;
  4013. +	// send name for wisp to player
  4014. +	WFIFOHEAD(fd, 3 + NAME_LENGTH);
  4015. +	WFIFOW(fd,0) = 0x2afb;
  4016. +	WFIFOB(fd,2) = 0;
  4017. +	memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
  4018. +	WFIFOSET(fd,3+NAME_LENGTH);
  4019.  
  4020. -		case 0x2afc: //Packet command is now used for sc_data request. [Skotlex]
  4021. -			if (RFIFOREST(fd) < 10)
  4022. -				return 0;
  4023. -		{
  4024. -#ifdef ENABLE_SC_SAVING
  4025. -			int aid, cid;
  4026. -			aid = RFIFOL(fd,2);
  4027. -			cid = RFIFOL(fd,6);
  4028. -			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
  4029. -				scdata_db, aid, cid) )
  4030. -			{
  4031. -				Sql_ShowDebug(sql_handle);
  4032. -				break;
  4033. -			}
  4034. -			if( Sql_NumRows(sql_handle) > 0 )
  4035. -			{
  4036. -				struct status_change_data scdata;
  4037. -				int count;
  4038. -				char* data;
  4039. +	char_send_fame_list(fd); //Send fame list.
  4040.  
  4041. -				WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
  4042. -				WFIFOW(fd,0) = 0x2b1d;
  4043. -				WFIFOL(fd,4) = aid;
  4044. -				WFIFOL(fd,8) = cid;
  4045. -				for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
  4046. -				{
  4047. -					Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
  4048. -					Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
  4049. -					Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
  4050. -					Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
  4051. -					Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
  4052. -					Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
  4053. -					memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
  4054. -				}
  4055. -				if (count >= 50)
  4056. -					ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
  4057. -				if (count > 0)
  4058. -				{
  4059. -					WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
  4060. -					WFIFOW(fd,12) = count;
  4061. +	{
  4062. +		unsigned char buf[16384];
  4063. +		int x;
  4064. +		if (j == 0) {
  4065. +			ShowWarning("Map-server %d has NO maps.\n", id);
  4066. +		} else {
  4067. +			// Transmitting maps information to the other map-servers
  4068. +			WBUFW(buf,0) = 0x2b04;
  4069. +			WBUFW(buf,2) = j * 4 + 10;
  4070. +			WBUFL(buf,4) = htonl(server[id].ip);
  4071. +			WBUFW(buf,8) = htons(server[id].port);
  4072. +			memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
  4073. +			mapif_sendallwos(fd, buf, WBUFW(buf,2));
  4074. +		}
  4075. +		// Transmitting the maps of the other map-servers to the new map-server
  4076. +		for(x = 0; x < ARRAYLENGTH(server); x++) {
  4077. +			if (server[x].fd > 0 && x != id) {
  4078. +				WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
  4079. +				WFIFOW(fd,0) = 0x2b04;
  4080. +				WFIFOL(fd,4) = htonl(server[x].ip);
  4081. +				WFIFOW(fd,8) = htons(server[x].port);
  4082. +				j = 0;
  4083. +				for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
  4084. +					if (server[x].map[i])
  4085. +						WFIFOW(fd,10+(j++)*4) = server[x].map[i];
  4086. +				if (j > 0) {
  4087. +					WFIFOW(fd,2) = j * 4 + 10;
  4088.  					WFIFOSET(fd,WFIFOW(fd,2));
  4089. -
  4090. -					//Clear the data once loaded.
  4091. -					if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
  4092. -						Sql_ShowDebug(sql_handle);
  4093.  				}
  4094.  			}
  4095. -			Sql_FreeResult(sql_handle);
  4096. -#endif
  4097. -			RFIFOSKIP(fd, 10);
  4098.  		}
  4099. -		break;
  4100. +	}
  4101. +	RFIFOSKIP(fd,RFIFOW(fd,2));
  4102. +	return 1;
  4103. +}
  4104.  
  4105. -		case 0x2afe: //set MAP user count
  4106. -			if (RFIFOREST(fd) < 4)
  4107. -				return 0;
  4108. -			if (RFIFOW(fd,2) != server[id].users) {
  4109. -				server[id].users = RFIFOW(fd,2);
  4110. -				ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
  4111. -			}
  4112. -			RFIFOSKIP(fd, 4);
  4113. -			break;
  4114. -
  4115. -		case 0x2aff: //set MAP users
  4116. -			if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  4117. -				return 0;
  4118. +int char_parsemap_askscdata(int fd, int id){
  4119. +	if (RFIFOREST(fd) < 10)
  4120. +		return 0;
  4121. +	{
  4122. +#ifdef ENABLE_SC_SAVING
  4123. +		int aid, cid;
  4124. +		aid = RFIFOL(fd,2);
  4125. +		cid = RFIFOL(fd,6);
  4126. +		if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
  4127. +			scdata_db, aid, cid) )
  4128.  		{
  4129. -			//TODO: When data mismatches memory, update guild/party online/offline states.
  4130. -			int aid, cid;
  4131. -			struct online_char_data* character;
  4132. -
  4133. -			server[id].users = RFIFOW(fd,4);
  4134. -			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
  4135. -			for(i = 0; i < server[id].users; i++) {
  4136. -				aid = RFIFOL(fd,6+i*8);
  4137. -				cid = RFIFOL(fd,6+i*8+4);
  4138. -				character = idb_ensure(online_char_db, aid, create_online_char_data);
  4139. -				if( character->server > -1 && character->server != id )
  4140. -				{
  4141. -					ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
  4142. -						character->account_id, character->char_id, character->server, id, aid, cid);
  4143. -					mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  4144. -				}
  4145. -				character->server = id;
  4146. -				character->char_id = cid;
  4147. -			}
  4148. -			//If any chars remain in -2, they will be cleaned in the cleanup timer.
  4149. -			RFIFOSKIP(fd,RFIFOW(fd,2));
  4150. +			Sql_ShowDebug(sql_handle);
  4151. +			return 0;
  4152.  		}
  4153. -		break;
  4154. -
  4155. -		case 0x2b01: // Receive character data from map-server for saving
  4156. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  4157. -				return 0;
  4158. +		if( Sql_NumRows(sql_handle) > 0 )
  4159.  		{
  4160. -			int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
  4161. -			struct online_char_data* character;
  4162. +			struct status_change_data scdata;
  4163. +			int count;
  4164. +			char* data;
  4165.  
  4166. -			if (size - 13 != sizeof(struct mmo_charstatus))
  4167. +			WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
  4168. +			WFIFOW(fd,0) = 0x2b1d;
  4169. +			WFIFOL(fd,4) = aid;
  4170. +			WFIFOL(fd,8) = cid;
  4171. +			for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
  4172.  			{
  4173. -				ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
  4174. -				RFIFOSKIP(fd,size);
  4175. -				break;
  4176. +				Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
  4177. +				Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
  4178. +				Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
  4179. +				Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
  4180. +				Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
  4181. +				Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
  4182. +				memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
  4183.  			}
  4184. -			//Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
  4185. -			if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
  4186. -				(character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
  4187. -				character->char_id == cid))
  4188. +			if (count >= 50)
  4189. +				ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
  4190. +			if (count > 0)
  4191.  			{
  4192. -				struct mmo_charstatus char_dat;
  4193. -				memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
  4194. -				mmo_char_tosql(cid, &char_dat);
  4195. -			} else {	//This may be valid on char-server reconnection, when re-sending characters that already logged off.
  4196. -				ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
  4197. -				set_char_online(id, cid, aid);
  4198. +				WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
  4199. +				WFIFOW(fd,12) = count;
  4200. +				WFIFOSET(fd,WFIFOW(fd,2));
  4201. +
  4202. +				//Clear the data once loaded.
  4203. +				if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
  4204. +					Sql_ShowDebug(sql_handle);
  4205.  			}
  4206. +		}
  4207. +		Sql_FreeResult(sql_handle);
  4208. +#endif
  4209. +		RFIFOSKIP(fd, 10);
  4210. +	}
  4211. +	return 1;
  4212. +}
  4213.  
  4214. -			if (RFIFOB(fd,12))
  4215. -			{	//Flag, set character offline after saving. [Skotlex]
  4216. -				set_char_offline(cid, aid);
  4217. -				WFIFOHEAD(fd,10);
  4218. -				WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
  4219. -				WFIFOL(fd,2) = aid;
  4220. -				WFIFOL(fd,6) = cid;
  4221. -				WFIFOSET(fd,10);
  4222. +int char_parsemap_getusercount(int fd, int id){
  4223. +	if (RFIFOREST(fd) < 4)
  4224. +		return 0;
  4225. +	if (RFIFOW(fd,2) != server[id].users) {
  4226. +		server[id].users = RFIFOW(fd,2);
  4227. +		ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
  4228. +	}
  4229. +	RFIFOSKIP(fd, 4);
  4230. +	return 1;
  4231. +}
  4232. +
  4233. +int char_parsemap_regmapuser(int fd, int id){
  4234. +	int i;
  4235. +	if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  4236. +		return 0;
  4237. +	{
  4238. +		//TODO: When data mismatches memory, update guild/party online/offline states.
  4239. +		int aid, cid;
  4240. +		struct online_char_data* character;
  4241. +
  4242. +		server[id].users = RFIFOW(fd,4);
  4243. +		online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
  4244. +		for(i = 0; i < server[id].users; i++) {
  4245. +			aid = RFIFOL(fd,6+i*8);
  4246. +			cid = RFIFOL(fd,6+i*8+4);
  4247. +			character = idb_ensure(online_char_db, aid, create_online_char_data);
  4248. +			if( character->server > -1 && character->server != id )
  4249. +			{
  4250. +				ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
  4251. +					character->account_id, character->char_id, character->server, id, aid, cid);
  4252. +				mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  4253.  			}
  4254. -			RFIFOSKIP(fd,size);
  4255. +			character->server = id;
  4256. +			character->char_id = cid;
  4257.  		}
  4258. -		break;
  4259. +		//If any chars remain in -2, they will be cleaned in the cleanup timer.
  4260. +		RFIFOSKIP(fd,RFIFOW(fd,2));
  4261. +	}
  4262. +	return 1;
  4263. +}
  4264.  
  4265. -		case 0x2b02: // req char selection
  4266. -			if( RFIFOREST(fd) < 18 )
  4267. -				return 0;
  4268. -			else{
  4269. -				int account_id = RFIFOL(fd,2);
  4270. -				uint32 login_id1 = RFIFOL(fd,6);
  4271. -				uint32 login_id2 = RFIFOL(fd,10);
  4272. -				uint32 ip = RFIFOL(fd,14);
  4273. -				RFIFOSKIP(fd,18);
  4274. +int char_parsemap_reqsavechar(int fd, int id){
  4275. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  4276. +			return 0;
  4277. +	{
  4278. +		int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
  4279. +		struct online_char_data* character;
  4280.  
  4281. -				if( runflag != CHARSERVER_ST_RUNNING ){
  4282. -					WFIFOHEAD(fd,7);
  4283. -					WFIFOW(fd,0) = 0x2b03;
  4284. -					WFIFOL(fd,2) = account_id;
  4285. -					WFIFOB(fd,6) = 0;// not ok
  4286. -					WFIFOSET(fd,7);
  4287. -				}else{
  4288. -					struct auth_node* node;
  4289. +		if (size - 13 != sizeof(struct mmo_charstatus))
  4290. +		{
  4291. +			ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
  4292. +			RFIFOSKIP(fd,size);
  4293. +			return 0;
  4294. +		}
  4295. +		//Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
  4296. +		if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
  4297. +			(character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
  4298. +			character->char_id == cid))
  4299. +		{
  4300. +			struct mmo_charstatus char_dat;
  4301. +			memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
  4302. +			mmo_char_tosql(cid, &char_dat);
  4303. +		} else {	//This may be valid on char-server reconnection, when re-sending characters that already logged off.
  4304. +			ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
  4305. +			set_char_online(id, cid, aid);
  4306. +		}
  4307.  
  4308. -					// create temporary auth entry
  4309. -					CREATE(node, struct auth_node, 1);
  4310. -					node->account_id = account_id;
  4311. -					node->char_id = 0;
  4312. -					node->login_id1 = login_id1;
  4313. -					node->login_id2 = login_id2;
  4314. -					//node->sex = 0;
  4315. -					node->ip = ntohl(ip);
  4316. -					//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
  4317. -					//node->gmlevel = 0;
  4318. -					idb_put(auth_db, account_id, node);
  4319. +		if (RFIFOB(fd,12))
  4320. +		{	//Flag, set character offline after saving. [Skotlex]
  4321. +			set_char_offline(cid, aid);
  4322. +			WFIFOHEAD(fd,10);
  4323. +			WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
  4324. +			WFIFOL(fd,2) = aid;
  4325. +			WFIFOL(fd,6) = cid;
  4326. +			WFIFOSET(fd,10);
  4327. +		}
  4328. +		RFIFOSKIP(fd,size);
  4329. +	}
  4330. +	return 1;
  4331. +}
  4332.  
  4333. -					//Set char to "@ char select" in online db [Kevin]
  4334. -					set_char_charselect(account_id);
  4335. +int char_parsemap_authok(int fd, int id){
  4336. +	if( RFIFOREST(fd) < 19 )
  4337. +		return 0;
  4338. +	else{
  4339. +		int account_id = RFIFOL(fd,2);
  4340. +		uint32 login_id1 = RFIFOL(fd,6);
  4341. +		uint32 login_id2 = RFIFOL(fd,10);
  4342. +		uint32 ip = RFIFOL(fd,14);
  4343. +		int version = RFIFOB(fd,18);
  4344. +		RFIFOSKIP(fd,19);
  4345.  
  4346. -					{
  4347. -						struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
  4348. +		if( runflag != CHARSERVER_ST_RUNNING ){
  4349. +			WFIFOHEAD(fd,7);
  4350. +			WFIFOW(fd,0) = 0x2b03;
  4351. +			WFIFOL(fd,2) = account_id;
  4352. +			WFIFOB(fd,6) = 0;// not ok
  4353. +			WFIFOSET(fd,7);
  4354. +		}else{
  4355. +			struct auth_node* node;
  4356.  
  4357. -						if( character != NULL ){
  4358. -							character->pincode_success = true;
  4359. -						}
  4360. -					}
  4361. +			// create temporary auth entry
  4362. +			CREATE(node, struct auth_node, 1);
  4363. +			node->account_id = account_id;
  4364. +			node->char_id = 0;
  4365. +			node->login_id1 = login_id1;
  4366. +			node->login_id2 = login_id2;
  4367. +			//node->sex = 0;
  4368. +			node->ip = ntohl(ip);
  4369. +			//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
  4370. +			//node->gmlevel = 0;
  4371. +			idb_put(auth_db, account_id, node);
  4372.  
  4373. -					WFIFOHEAD(fd,7);
  4374. -					WFIFOW(fd,0) = 0x2b03;
  4375. -					WFIFOL(fd,2) = account_id;
  4376. -					WFIFOB(fd,6) = 1;// ok
  4377. -					WFIFOSET(fd,7);
  4378. +			//Set char to "@ char select" in online db [Kevin]
  4379. +			set_char_charselect(account_id);
  4380. +			{
  4381. +				struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
  4382. +				if( character != NULL ){
  4383. +					character->pincode_success = true;
  4384. +					character->version = version;
  4385.  				}
  4386.  			}
  4387. -		break;
  4388.  
  4389. -		case 0x2b05: // request "change map server"
  4390. -			if (RFIFOREST(fd) < 39)
  4391. -				return 0;
  4392. -		{
  4393. -			int map_id, map_fd = -1;
  4394. -			struct mmo_charstatus* char_data;
  4395. -			struct mmo_charstatus char_dat;
  4396. +			WFIFOHEAD(fd,7);
  4397. +			WFIFOW(fd,0) = 0x2b03;
  4398. +			WFIFOL(fd,2) = account_id;
  4399. +			WFIFOB(fd,6) = 1;// ok
  4400. +			WFIFOSET(fd,7);
  4401. +		}
  4402. +	}
  4403. +	return 1;
  4404. +}
  4405.  
  4406. -			map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
  4407. -			if (map_id >= 0)
  4408. -				map_fd = server[map_id].fd;
  4409. -			//Char should just had been saved before this packet, so this should be safe. [Skotlex]
  4410. +int char_parsemap_reqchangemapserv(int fd, int id){
  4411. +	if (RFIFOREST(fd) < 39)
  4412. +		return 0;
  4413. +	{
  4414. +		int map_id, map_fd = -1;
  4415. +		struct mmo_charstatus* char_data;
  4416. +		struct mmo_charstatus char_dat;
  4417. +
  4418. +		map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
  4419. +		if (map_id >= 0)
  4420. +			map_fd = server[map_id].fd;
  4421. +		//Char should just had been saved before this packet, so this should be safe. [Skotlex]
  4422. +		char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  4423. +		if (char_data == NULL) {	//Really shouldn't happen.
  4424. +			mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
  4425.  			char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  4426. -			if (char_data == NULL) {	//Really shouldn't happen.
  4427. -				mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
  4428. -				char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  4429. -			}
  4430. +		}
  4431.  
  4432. -			if( runflag == CHARSERVER_ST_RUNNING &&
  4433. -				session_isActive(map_fd) &&
  4434. -				char_data )
  4435. -			{	//Send the map server the auth of this player.
  4436. -				struct online_char_data* data;
  4437. -				struct auth_node* node;
  4438. +		if( runflag == CHARSERVER_ST_RUNNING &&
  4439. +			session_isActive(map_fd) &&
  4440. +			char_data )
  4441. +		{	//Send the map server the auth of this player.
  4442. +			struct online_char_data* data;
  4443. +			struct auth_node* node;
  4444.  
  4445. -				//Update the "last map" as this is where the player must be spawned on the new map server.
  4446. -				char_data->last_point.map = RFIFOW(fd,18);
  4447. -				char_data->last_point.x = RFIFOW(fd,20);
  4448. -				char_data->last_point.y = RFIFOW(fd,22);
  4449. -				char_data->sex = RFIFOB(fd,30);
  4450. +			int aid = RFIFOL(fd,2);
  4451.  
  4452. -				// create temporary auth entry
  4453. -				CREATE(node, struct auth_node, 1);
  4454. -				node->account_id = RFIFOL(fd,2);
  4455. -				node->char_id = RFIFOL(fd,14);
  4456. -				node->login_id1 = RFIFOL(fd,6);
  4457. -				node->login_id2 = RFIFOL(fd,10);
  4458. -				node->sex = RFIFOB(fd,30);
  4459. -				node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
  4460. -				node->ip = ntohl(RFIFOL(fd,31));
  4461. -				node->group_id = RFIFOL(fd,35);
  4462. -				node->changing_mapservers = 1;
  4463. -				idb_put(auth_db, RFIFOL(fd,2), node);
  4464. +			//Update the "last map" as this is where the player must be spawned on the new map server.
  4465. +			char_data->last_point.map = RFIFOW(fd,18);
  4466. +			char_data->last_point.x = RFIFOW(fd,20);
  4467. +			char_data->last_point.y = RFIFOW(fd,22);
  4468. +			char_data->sex = RFIFOB(fd,30);
  4469.  
  4470. -				data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
  4471. -				data->char_id = char_data->char_id;
  4472. -				data->server = map_id; //Update server where char is.
  4473. +			// create temporary auth entry
  4474. +			CREATE(node, struct auth_node, 1);
  4475. +			node->account_id = aid;
  4476. +			node->char_id = RFIFOL(fd,14);
  4477. +			node->login_id1 = RFIFOL(fd,6);
  4478. +			node->login_id2 = RFIFOL(fd,10);
  4479. +			node->sex = RFIFOB(fd,30);
  4480. +			node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
  4481. +			node->ip = ntohl(RFIFOL(fd,31));
  4482. +			node->group_id = RFIFOL(fd,35);
  4483. +			node->changing_mapservers = 1;
  4484. +			idb_put(auth_db, aid, node);
  4485.  
  4486. -				//Reply with an ack.
  4487. -				WFIFOHEAD(fd,30);
  4488. -				WFIFOW(fd,0) = 0x2b06;
  4489. -				memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  4490. -				WFIFOSET(fd,30);
  4491. -			} else { //Reply with nak
  4492. -				WFIFOHEAD(fd,30);
  4493. -				WFIFOW(fd,0) = 0x2b06;
  4494. -				memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  4495. -				WFIFOL(fd,6) = 0; //Set login1 to 0.
  4496. -				WFIFOSET(fd,30);
  4497. -			}
  4498. -			RFIFOSKIP(fd,39);
  4499. +			data = idb_ensure(online_char_db, aid, create_online_char_data);
  4500. +			data->char_id = char_data->char_id;
  4501. +			data->server = map_id; //Update server where char is.
  4502. +
  4503. +			//Reply with an ack.
  4504. +			WFIFOHEAD(fd,30);
  4505. +			WFIFOW(fd,0) = 0x2b06;
  4506. +			memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  4507. +			WFIFOSET(fd,30);
  4508. +		} else { //Reply with nak
  4509. +			WFIFOHEAD(fd,30);
  4510. +			WFIFOW(fd,0) = 0x2b06;
  4511. +			memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  4512. +			WFIFOL(fd,6) = 0; //Set login1 to 0.
  4513. +			WFIFOSET(fd,30);
  4514.  		}
  4515. -		break;
  4516. +		RFIFOSKIP(fd,39);
  4517. +	}
  4518. +	return 1;
  4519. +}
  4520.  
  4521. -		case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
  4522. -			if (RFIFOREST(fd) < 10)
  4523. -				return 0;
  4524. -			{
  4525. -				int char_id, friend_id;
  4526. -				char_id = RFIFOL(fd,2);
  4527. -				friend_id = RFIFOL(fd,6);
  4528. -				if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
  4529. -					friend_db, char_id, friend_id) ) {
  4530. -					Sql_ShowDebug(sql_handle);
  4531. -					break;
  4532. -				}
  4533. -				RFIFOSKIP(fd,10);
  4534. -			}
  4535. -		break;
  4536. +int char_parsemap_askrmfriend(int fd, int id){
  4537. +	if (RFIFOREST(fd) < 10)
  4538. +		return 0;
  4539. +	{
  4540. +		int char_id, friend_id;
  4541. +		char_id = RFIFOL(fd,2);
  4542. +		friend_id = RFIFOL(fd,6);
  4543. +		if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
  4544. +			friend_db, char_id, friend_id) ) {
  4545. +			Sql_ShowDebug(sql_handle);
  4546. +			return 0;
  4547. +		}
  4548. +		RFIFOSKIP(fd,10);
  4549. +	}
  4550. +	return 1;
  4551. +}
  4552.  
  4553. -		case 0x2b08: // char name request
  4554. -			if (RFIFOREST(fd) < 6)
  4555. -				return 0;
  4556. +int char_parsemap_reqcharname(int fd, int id){
  4557. +	if (RFIFOREST(fd) < 6)
  4558. +		return 0;
  4559.  
  4560. -			WFIFOHEAD(fd,30);
  4561. -			WFIFOW(fd,0) = 0x2b09;
  4562. -			WFIFOL(fd,2) = RFIFOL(fd,2);
  4563. -			char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
  4564. -			WFIFOSET(fd,30);
  4565. +	WFIFOHEAD(fd,30);
  4566. +	WFIFOW(fd,0) = 0x2b09;
  4567. +	WFIFOL(fd,2) = RFIFOL(fd,2);
  4568. +	char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
  4569. +	WFIFOSET(fd,30);
  4570.  
  4571. -			RFIFOSKIP(fd,6);
  4572. -		break;
  4573. +	RFIFOSKIP(fd,6);
  4574. +	return 1;
  4575. +}
  4576.  
  4577. -		case 0x2b0c: // Map server send information to change an email of an account -> login-server
  4578. -			if (RFIFOREST(fd) < 86)
  4579. -				return 0;
  4580. -			if (login_fd > 0) { // don't send request if no login-server
  4581. -				WFIFOHEAD(login_fd,86);
  4582. -				memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  4583. -				WFIFOW(login_fd,0) = 0x2722;
  4584. -				WFIFOSET(login_fd,86);
  4585. -			}
  4586. -			RFIFOSKIP(fd, 86);
  4587. -		break;
  4588. +/*
  4589. + * Forward email update request to loginserv
  4590. + */
  4591. +int char_parsemap_reqnewemail(int fd, int id){
  4592. +	if (RFIFOREST(fd) < 86)
  4593. +		return 0;
  4594. +	if (login_fd > 0) { // don't send request if no login-server
  4595. +		WFIFOHEAD(login_fd,86);
  4596. +		memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  4597. +		WFIFOW(login_fd,0) = 0x2722;
  4598. +		WFIFOSET(login_fd,86);
  4599. +	}
  4600. +	RFIFOSKIP(fd, 86);
  4601. +	return 1;
  4602. +}
  4603.  
  4604. -		case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server)
  4605. -			if (RFIFOREST(fd) < 44)
  4606. -				return 0;
  4607. -		{
  4608. -			int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
  4609. -			char esc_name[NAME_LENGTH*2+1];
  4610. +int char_parsemap_fwlog_changestatus(int fd, int id){
  4611. +	if (RFIFOREST(fd) < 44)
  4612. +		return 0;
  4613. +	{
  4614. +		int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
  4615. +		char esc_name[NAME_LENGTH*2+1];
  4616.  
  4617. -			int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
  4618. -			const char* name = (char*)RFIFOP(fd,6); // name of the target character
  4619. -			int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
  4620. -			short year = RFIFOW(fd,32);
  4621. -			short month = RFIFOW(fd,34);
  4622. -			short day = RFIFOW(fd,36);
  4623. -			short hour = RFIFOW(fd,38);
  4624. -			short minute = RFIFOW(fd,40);
  4625. -			short second = RFIFOW(fd,42);
  4626. -			RFIFOSKIP(fd,44);
  4627. +		int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
  4628. +		const char* name = (char*)RFIFOP(fd,6); // name of the target character
  4629. +		int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
  4630. +		short year = RFIFOW(fd,32);
  4631. +		short month = RFIFOW(fd,34);
  4632. +		short day = RFIFOW(fd,36);
  4633. +		short hour = RFIFOW(fd,38);
  4634. +		short minute = RFIFOW(fd,40);
  4635. +		short second = RFIFOW(fd,42);
  4636. +		RFIFOSKIP(fd,44);
  4637.  
  4638. -			Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  4639. -			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
  4640. -				Sql_ShowDebug(sql_handle);
  4641. -			else
  4642. -			if( Sql_NumRows(sql_handle) == 0 )
  4643. -			{
  4644. -				result = 1; // 1-player not found
  4645. -			}
  4646. -			else
  4647. -			if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  4648. -				Sql_ShowDebug(sql_handle);
  4649. -				//FIXME: set proper result value?
  4650. -			else
  4651. -			{
  4652. -				char name[NAME_LENGTH];
  4653. -				int account_id;
  4654. -				char* data;
  4655. +		Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  4656. +		if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
  4657. +			Sql_ShowDebug(sql_handle);
  4658. +		else
  4659. +		if( Sql_NumRows(sql_handle) == 0 )
  4660. +		{
  4661. +			result = 1; // 1-player not found
  4662. +		}
  4663. +		else
  4664. +		if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  4665. +			Sql_ShowDebug(sql_handle);
  4666. +			//FIXME: set proper result value?
  4667. +		else
  4668. +		{
  4669. +			char name[NAME_LENGTH];
  4670. +			int account_id;
  4671. +			char* data;
  4672.  
  4673. -				Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
  4674. -				Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
  4675. +			Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
  4676. +			Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
  4677.  
  4678. -				if( login_fd <= 0 )
  4679. -					result = 3; // 3-login-server offline
  4680. -				//FIXME: need to move this check to login server [ultramage]
  4681. +			if( login_fd <= 0 )
  4682. +				result = 3; // 3-login-server offline
  4683. +			//FIXME: need to move this check to login server [ultramage]
  4684.  //				else
  4685.  //				if( acc != -1 && isGM(acc) < isGM(account_id) )
  4686.  //					result = 2; // 2-gm level too low
  4687. -				else
  4688. -				switch( type ) {
  4689. -				case 1: // block
  4690. -						WFIFOHEAD(login_fd,10);
  4691. -						WFIFOW(login_fd,0) = 0x2724;
  4692. -						WFIFOL(login_fd,2) = account_id;
  4693. -						WFIFOL(login_fd,6) = 5; // new account status
  4694. -						WFIFOSET(login_fd,10);
  4695. -				break;
  4696. -				case 2: // ban
  4697. -						WFIFOHEAD(login_fd,18);
  4698. -						WFIFOW(login_fd, 0) = 0x2725;
  4699. -						WFIFOL(login_fd, 2) = account_id;
  4700. -						WFIFOW(login_fd, 6) = year;
  4701. -						WFIFOW(login_fd, 8) = month;
  4702. -						WFIFOW(login_fd,10) = day;
  4703. -						WFIFOW(login_fd,12) = hour;
  4704. -						WFIFOW(login_fd,14) = minute;
  4705. -						WFIFOW(login_fd,16) = second;
  4706. -						WFIFOSET(login_fd,18);
  4707. -				break;
  4708. -				case 3: // unblock
  4709. -						WFIFOHEAD(login_fd,10);
  4710. -						WFIFOW(login_fd,0) = 0x2724;
  4711. -						WFIFOL(login_fd,2) = account_id;
  4712. -						WFIFOL(login_fd,6) = 0; // new account status
  4713. -						WFIFOSET(login_fd,10);
  4714. -				break;
  4715. -				case 4: // unban
  4716. -						WFIFOHEAD(login_fd,6);
  4717. -						WFIFOW(login_fd,0) = 0x272a;
  4718. -						WFIFOL(login_fd,2) = account_id;
  4719. -						WFIFOSET(login_fd,6);
  4720. -				break;
  4721. -				case 5: // changesex
  4722. -						WFIFOHEAD(login_fd,6);
  4723. -						WFIFOW(login_fd,0) = 0x2727;
  4724. -						WFIFOL(login_fd,2) = account_id;
  4725. -						WFIFOSET(login_fd,6);
  4726. -				break;
  4727. -				}
  4728. +			else
  4729. +			switch( type ) {
  4730. +			case 1: // block
  4731. +					WFIFOHEAD(login_fd,10);
  4732. +					WFIFOW(login_fd,0) = 0x2724;
  4733. +					WFIFOL(login_fd,2) = account_id;
  4734. +					WFIFOL(login_fd,6) = 5; // new account status
  4735. +					WFIFOSET(login_fd,10);
  4736. +			break;
  4737. +			case 2: // ban
  4738. +					WFIFOHEAD(login_fd,18);
  4739. +					WFIFOW(login_fd, 0) = 0x2725;
  4740. +					WFIFOL(login_fd, 2) = account_id;
  4741. +					WFIFOW(login_fd, 6) = year;
  4742. +					WFIFOW(login_fd, 8) = month;
  4743. +					WFIFOW(login_fd,10) = day;
  4744. +					WFIFOW(login_fd,12) = hour;
  4745. +					WFIFOW(login_fd,14) = minute;
  4746. +					WFIFOW(login_fd,16) = second;
  4747. +					WFIFOSET(login_fd,18);
  4748. +			break;
  4749. +			case 3: // unblock
  4750. +					WFIFOHEAD(login_fd,10);
  4751. +					WFIFOW(login_fd,0) = 0x2724;
  4752. +					WFIFOL(login_fd,2) = account_id;
  4753. +					WFIFOL(login_fd,6) = 0; // new account status
  4754. +					WFIFOSET(login_fd,10);
  4755. +			break;
  4756. +			case 4: // unban
  4757. +					WFIFOHEAD(login_fd,6);
  4758. +					WFIFOW(login_fd,0) = 0x272a;
  4759. +					WFIFOL(login_fd,2) = account_id;
  4760. +					WFIFOSET(login_fd,6);
  4761. +			break;
  4762. +			case 5: // changesex
  4763. +					WFIFOHEAD(login_fd,6);
  4764. +					WFIFOW(login_fd,0) = 0x2727;
  4765. +					WFIFOL(login_fd,2) = account_id;
  4766. +					WFIFOSET(login_fd,6);
  4767. +			break;
  4768.  			}
  4769. +		}
  4770.  
  4771. -			Sql_FreeResult(sql_handle);
  4772. +		Sql_FreeResult(sql_handle);
  4773.  
  4774. -			// send answer if a player ask, not if the server ask
  4775. -			if( acc != -1 && type != 5) { // Don't send answer for changesex
  4776. -				WFIFOHEAD(fd,34);
  4777. -				WFIFOW(fd, 0) = 0x2b0f;
  4778. -				WFIFOL(fd, 2) = acc;
  4779. -				safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
  4780. -				WFIFOW(fd,30) = type;
  4781. -				WFIFOW(fd,32) = result;
  4782. -				WFIFOSET(fd,34);
  4783. -			}
  4784. +		// send answer if a player ask, not if the server ask
  4785. +		if( acc != -1 && type != 5) { // Don't send answer for changesex
  4786. +			WFIFOHEAD(fd,34);
  4787. +			WFIFOW(fd, 0) = 0x2b0f;
  4788. +			WFIFOL(fd, 2) = acc;
  4789. +			safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
  4790. +			WFIFOW(fd,30) = type;
  4791. +			WFIFOW(fd,32) = result;
  4792. +			WFIFOSET(fd,34);
  4793.  		}
  4794. -		break;
  4795. +	}
  4796. +	return 1;
  4797. +}
  4798.  
  4799. -		case 0x2b10: // Update and send fame ranking list
  4800. -			if (RFIFOREST(fd) < 11)
  4801. -				return 0;
  4802. +int char_parsemap_updfamelist(int fd, int id){
  4803. +	if (RFIFOREST(fd) < 11)
  4804. +		return 0;
  4805. +	{
  4806. +		int cid = RFIFOL(fd, 2);
  4807. +		int fame = RFIFOL(fd, 6);
  4808. +		char type = RFIFOB(fd, 10);
  4809. +		int size;
  4810. +		struct fame_list* list;
  4811. +		int player_pos;
  4812. +		int fame_pos;
  4813. +
  4814. +		switch(type)
  4815.  		{
  4816. -			int cid = RFIFOL(fd, 2);
  4817. -			int fame = RFIFOL(fd, 6);
  4818. -			char type = RFIFOB(fd, 10);
  4819. -			int size;
  4820. -			struct fame_list* list;
  4821. -			int player_pos;
  4822. -			int fame_pos;
  4823. +			case 1:  size = fame_list_size_smith;   list = smith_fame_list;   break;
  4824. +			case 2:  size = fame_list_size_chemist; list = chemist_fame_list; break;
  4825. +			case 3:  size = fame_list_size_taekwon; list = taekwon_fame_list; break;
  4826. +			default: size = 0;                      list = NULL;              break;
  4827. +		}
  4828.  
  4829. -			switch(type)
  4830. -			{
  4831. -				case 1:  size = fame_list_size_smith;   list = smith_fame_list;   break;
  4832. -				case 2:  size = fame_list_size_chemist; list = chemist_fame_list; break;
  4833. -				case 3:  size = fame_list_size_taekwon; list = taekwon_fame_list; break;
  4834. -				default: size = 0;                      list = NULL;              break;
  4835. -			}
  4836. +		ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
  4837. +		ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
  4838.  
  4839. -			ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
  4840. -			ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
  4841. -
  4842. -			if( player_pos == size && fame_pos == size )
  4843. -				;// not on list and not enough fame to get on it
  4844. -			else if( fame_pos == player_pos )
  4845. -			{// same position
  4846. -				list[player_pos].fame = fame;
  4847. -				char_update_fame_list(type, player_pos, fame);
  4848. +		if( player_pos == size && fame_pos == size )
  4849. +			;// not on list and not enough fame to get on it
  4850. +		else if( fame_pos == player_pos )
  4851. +		{// same position
  4852. +			list[player_pos].fame = fame;
  4853. +			char_update_fame_list(type, player_pos, fame);
  4854. +		}
  4855. +		else
  4856. +		{// move in the list
  4857. +			if( player_pos == size )
  4858. +			{// new ranker - not in the list
  4859. +				ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
  4860. +				list[fame_pos].id = cid;
  4861. +				list[fame_pos].fame = fame;
  4862. +				char_loadName(cid, list[fame_pos].name);
  4863.  			}
  4864.  			else
  4865. -			{// move in the list
  4866. -				if( player_pos == size )
  4867. -				{// new ranker - not in the list
  4868. -					ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
  4869. -					list[fame_pos].id = cid;
  4870. -					list[fame_pos].fame = fame;
  4871. -					char_loadName(cid, list[fame_pos].name);
  4872. -				}
  4873. -				else
  4874. -				{// already in the list
  4875. -					if( fame_pos == size )
  4876. -						--fame_pos;// move to the end of the list
  4877. -					ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
  4878. -					list[fame_pos].fame = fame;
  4879. -				}
  4880. -				char_send_fame_list(-1);
  4881. +			{// already in the list
  4882. +				if( fame_pos == size )
  4883. +					--fame_pos;// move to the end of the list
  4884. +				ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
  4885. +				list[fame_pos].fame = fame;
  4886.  			}
  4887. -
  4888. -			RFIFOSKIP(fd,11);
  4889. +			char_send_fame_list(-1);
  4890.  		}
  4891. -		break;
  4892.  
  4893. -		// Divorce chars
  4894. -		case 0x2b11:
  4895. -			if( RFIFOREST(fd) < 10 )
  4896. -				return 0;
  4897. -			divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
  4898. -			RFIFOSKIP(fd,10);
  4899. -		break;
  4900. +		RFIFOSKIP(fd,11);
  4901. +	}
  4902. +	return 1;
  4903. +}
  4904.  
  4905. -		case 0x2b16: // Receive rates [Wizputer]
  4906. -			if( RFIFOREST(fd) < 14 )
  4907. -				return 0;
  4908. -		{
  4909. -			char esc_server_name[sizeof(server_name)*2+1];
  4910. +int char_parsemap_reqdivorce(int fd, int id){
  4911. +	if( RFIFOREST(fd) < 10 )
  4912. +		return 0;
  4913. +	divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
  4914. +	RFIFOSKIP(fd,10);
  4915. +	return 1;
  4916. +}
  4917. +int char_parsemap_updmapinfo(int fd, int id){
  4918. +	if( RFIFOREST(fd) < 14 )
  4919. +		return 0;
  4920. +	{
  4921. +		char esc_server_name[sizeof(server_name)*2+1];
  4922.  
  4923. -			Sql_EscapeString(sql_handle, esc_server_name, server_name);
  4924. +		Sql_EscapeString(sql_handle, esc_server_name, server_name);
  4925.  
  4926. -			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
  4927. -				ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
  4928. -				Sql_ShowDebug(sql_handle);
  4929. -			RFIFOSKIP(fd,14);
  4930. -		}
  4931. -		break;
  4932. +		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
  4933. +			ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
  4934. +			Sql_ShowDebug(sql_handle);
  4935. +		RFIFOSKIP(fd,14);
  4936. +	}
  4937. +	return 1;
  4938. +}
  4939. +int char_parsemap_setcharoffline(int fd, int id){
  4940. +	if (RFIFOREST(fd) < 6)
  4941. +		return 0;
  4942. +	set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
  4943. +	RFIFOSKIP(fd,10);
  4944. +	return 1;
  4945. +}
  4946. +int char_parsemap_setalloffline(int fd, int id){
  4947. +	set_all_offline(id);
  4948. +	RFIFOSKIP(fd,2);
  4949. +	return 1;
  4950. +}
  4951. +int char_parsemap_setcharonline(int fd, int id){
  4952. +	if (RFIFOREST(fd) < 10)
  4953. +		return 0;
  4954. +	set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
  4955. +	RFIFOSKIP(fd,10);
  4956. +	return 1;
  4957. +}
  4958. +int char_parsemap_reqfamelist(int fd, int id){
  4959. +	if (RFIFOREST(fd) < 2)
  4960. +		return 0;
  4961. +	char_read_fame_list();
  4962. +	char_send_fame_list(-1);
  4963. +	RFIFOSKIP(fd,2);
  4964. +	return 1;
  4965. +}
  4966.  
  4967. -		case 0x2b17: // Character disconnected set online 0 [Wizputer]
  4968. -			if (RFIFOREST(fd) < 6)
  4969. -				return 0;
  4970. -			set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
  4971. -			RFIFOSKIP(fd,10);
  4972. -		break;
  4973. +int char_parsemap_save_scdata(int fd, int id){
  4974. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  4975. +		return 0;
  4976. +	{
  4977. +#ifdef ENABLE_SC_SAVING
  4978. +		int count, aid, cid;
  4979.  
  4980. -		case 0x2b18: // Reset all chars to offline [Wizputer]
  4981. -			set_all_offline(id);
  4982. -			RFIFOSKIP(fd,2);
  4983. -		break;
  4984. +		aid = RFIFOL(fd, 4);
  4985. +		cid = RFIFOL(fd, 8);
  4986. +		count = RFIFOW(fd, 12);
  4987.  
  4988. -		case 0x2b19: // Character set online [Wizputer]
  4989. -			if (RFIFOREST(fd) < 10)
  4990. -				return 0;
  4991. -			set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
  4992. -			RFIFOSKIP(fd,10);
  4993. -		break;
  4994. -
  4995. -		case 0x2b1a: // Build and send fame ranking lists [DracoRPG]
  4996. -			if (RFIFOREST(fd) < 2)
  4997. -				return 0;
  4998. -			char_read_fame_list();
  4999. -			char_send_fame_list(-1);
  5000. -			RFIFOSKIP(fd,2);
  5001. -		break;
  5002. -
  5003. -		case 0x2b1c: //Request to save status change data. [Skotlex]
  5004. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  5005. -				return 0;
  5006. +		if( count > 0 )
  5007.  		{
  5008. -#ifdef ENABLE_SC_SAVING
  5009. -			int count, aid, cid;
  5010. +			struct status_change_data data;
  5011. +			StringBuf buf;
  5012. +			int i;
  5013.  
  5014. -			aid = RFIFOL(fd, 4);
  5015. -			cid = RFIFOL(fd, 8);
  5016. -			count = RFIFOW(fd, 12);
  5017. -
  5018. -			if( count > 0 )
  5019. +			StringBuf_Init(&buf);
  5020. +			StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
  5021. +			for( i = 0; i < count; ++i )
  5022.  			{
  5023. -				struct status_change_data data;
  5024. -				StringBuf buf;
  5025. -				int i;
  5026. -
  5027. -				StringBuf_Init(&buf);
  5028. -				StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
  5029. -				for( i = 0; i < count; ++i )
  5030. -				{
  5031. -					memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
  5032. -					if( i > 0 )
  5033. -						StringBuf_AppendStr(&buf, ", ");
  5034. -					StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
  5035. -						data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
  5036. -				}
  5037. -				if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
  5038. -					Sql_ShowDebug(sql_handle);
  5039. -				StringBuf_Destroy(&buf);
  5040. +				memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
  5041. +				if( i > 0 )
  5042. +					StringBuf_AppendStr(&buf, ", ");
  5043. +				StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
  5044. +					data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
  5045.  			}
  5046. +			if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
  5047. +				Sql_ShowDebug(sql_handle);
  5048. +			StringBuf_Destroy(&buf);
  5049. +		}
  5050.  #endif
  5051. -			RFIFOSKIP(fd, RFIFOW(fd, 2));
  5052. -		}
  5053. -		break;
  5054. +		RFIFOSKIP(fd, RFIFOW(fd, 2));
  5055. +	}
  5056. +	return 1;
  5057. +}
  5058.  
  5059. -		case 0x2b23: // map-server alive packet
  5060. -			WFIFOHEAD(fd,2);
  5061. -			WFIFOW(fd,0) = 0x2b24;
  5062. -			WFIFOSET(fd,2);
  5063. -			RFIFOSKIP(fd,2);
  5064. -		break;
  5065. +int char_parsemap_keepalive(int fd, int id){
  5066. +	WFIFOHEAD(fd,2);
  5067. +	WFIFOW(fd,0) = 0x2b24;
  5068. +	WFIFOSET(fd,2);
  5069. +	RFIFOSKIP(fd,2);
  5070. +	return 1;
  5071. +}
  5072.  
  5073. -		case 0x2b26: // auth request from map-server
  5074. -			if (RFIFOREST(fd) < 19)
  5075. -				return 0;
  5076. +int char_parsemap_reqauth(int fd, int id){
  5077. +	if (RFIFOREST(fd) < 19)
  5078. +		return 0;
  5079.  
  5080. -		{
  5081. -			int account_id;
  5082. -			int char_id;
  5083. -			int login_id1;
  5084. -			char sex;
  5085. -			uint32 ip;
  5086. -			struct auth_node* node;
  5087. -			struct mmo_charstatus* cd;
  5088. -			struct mmo_charstatus char_dat;
  5089. +	{
  5090. +		int account_id;
  5091. +		int char_id;
  5092. +		int login_id1;
  5093. +		char sex;
  5094. +		uint32 ip;
  5095. +		struct auth_node* node;
  5096. +		struct mmo_charstatus* cd;
  5097. +		struct mmo_charstatus char_dat;
  5098.  
  5099. -			account_id = RFIFOL(fd,2);
  5100. -			char_id    = RFIFOL(fd,6);
  5101. -			login_id1  = RFIFOL(fd,10);
  5102. -			sex        = RFIFOB(fd,14);
  5103. -			ip         = ntohl(RFIFOL(fd,15));
  5104. -			RFIFOSKIP(fd,19);
  5105. +		account_id = RFIFOL(fd,2);
  5106. +		char_id    = RFIFOL(fd,6);
  5107. +		login_id1  = RFIFOL(fd,10);
  5108. +		sex        = RFIFOB(fd,14);
  5109. +		ip         = ntohl(RFIFOL(fd,15));
  5110. +		RFIFOSKIP(fd,19);
  5111.  
  5112. -			node = (struct auth_node*)idb_get(auth_db, account_id);
  5113. +		node = (struct auth_node*)idb_get(auth_db, account_id);
  5114. +		cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  5115. +		if( cd == NULL )
  5116. +		{	//Really shouldn't happen.
  5117. +			mmo_char_fromsql(char_id, &char_dat, true);
  5118.  			cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  5119. -			if( cd == NULL )
  5120. -			{	//Really shouldn't happen.
  5121. -				mmo_char_fromsql(char_id, &char_dat, true);
  5122. -				cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  5123. -			}
  5124. -			if( runflag == CHARSERVER_ST_RUNNING &&
  5125. -				cd != NULL &&
  5126. -				node != NULL &&
  5127. -				node->account_id == account_id &&
  5128. -				node->char_id == char_id &&
  5129. -				node->login_id1 == login_id1 &&
  5130. -				node->sex == sex /*&&
  5131. -				node->ip == ip*/ )
  5132. -			{// auth ok
  5133. -				cd->sex = sex;
  5134. +		}
  5135. +		if( runflag == CHARSERVER_ST_RUNNING &&
  5136. +			cd != NULL &&
  5137. +			node != NULL &&
  5138. +			node->account_id == account_id &&
  5139. +			node->char_id == char_id &&
  5140. +			node->login_id1 == login_id1 &&
  5141. +			node->sex == sex /*&&
  5142. +			node->ip == ip*/ )
  5143. +		{// auth ok
  5144. +			cd->sex = sex;
  5145.  
  5146. -				WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
  5147. -				WFIFOW(fd,0) = 0x2afd;
  5148. -				WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
  5149. -				WFIFOL(fd,4) = account_id;
  5150. -				WFIFOL(fd,8) = node->login_id1;
  5151. -				WFIFOL(fd,12) = node->login_id2;
  5152. -				WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
  5153. -				WFIFOL(fd,20) = node->group_id;
  5154. -				WFIFOB(fd,24) = node->changing_mapservers;
  5155. -				memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
  5156. -				WFIFOSET(fd, WFIFOW(fd,2));
  5157. +			WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
  5158. +			WFIFOW(fd,0) = 0x2afd;
  5159. +			WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
  5160. +			WFIFOL(fd,4) = account_id;
  5161. +			WFIFOL(fd,8) = node->login_id1;
  5162. +			WFIFOL(fd,12) = node->login_id2;
  5163. +			WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
  5164. +			WFIFOL(fd,20) = node->group_id;
  5165. +			WFIFOB(fd,24) = node->changing_mapservers;
  5166. +			memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
  5167. +			WFIFOSET(fd, WFIFOW(fd,2));
  5168.  
  5169. -				// only use the auth once and mark user online
  5170. -				idb_remove(auth_db, account_id);
  5171. -				set_char_online(id, char_id, account_id);
  5172. -			}
  5173. -			else
  5174. -			{// auth failed
  5175. -				WFIFOHEAD(fd,19);
  5176. -				WFIFOW(fd,0) = 0x2b27;
  5177. -				WFIFOL(fd,2) = account_id;
  5178. -				WFIFOL(fd,6) = char_id;
  5179. -				WFIFOL(fd,10) = login_id1;
  5180. -				WFIFOB(fd,14) = sex;
  5181. -				WFIFOL(fd,15) = htonl(ip);
  5182. -				WFIFOSET(fd,19);
  5183. -			}
  5184. +			// only use the auth once and mark user online
  5185. +			idb_remove(auth_db, account_id);
  5186. +			set_char_online(id, char_id, account_id);
  5187.  		}
  5188. -		break;
  5189. +		else
  5190. +		{// auth failed
  5191. +			WFIFOHEAD(fd,19);
  5192. +			WFIFOW(fd,0) = 0x2b27;
  5193. +			WFIFOL(fd,2) = account_id;
  5194. +			WFIFOL(fd,6) = char_id;
  5195. +			WFIFOL(fd,10) = login_id1;
  5196. +			WFIFOB(fd,14) = sex;
  5197. +			WFIFOL(fd,15) = htonl(ip);
  5198. +			WFIFOSET(fd,19);
  5199. +		}
  5200. +	}
  5201. +	return 1;
  5202. +}
  5203.  
  5204. -		case 0x2736: // ip address update
  5205. -			if (RFIFOREST(fd) < 6) return 0;
  5206. -			server[id].ip = ntohl(RFIFOL(fd, 2));
  5207. -			ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
  5208. -			RFIFOSKIP(fd,6);
  5209. -		break;
  5210. +int char_parsemap_updmapip(int fd, int id){
  5211. +	if (RFIFOREST(fd) < 6) return 0;
  5212. +	server[id].ip = ntohl(RFIFOL(fd, 2));
  5213. +	ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
  5214. +	RFIFOSKIP(fd,6);
  5215. +	return 1;
  5216. +}
  5217.  
  5218. -		case 0x3008:
  5219. -			if( RFIFOREST(fd) < RFIFOW(fd,4) )
  5220. -				return 0;/* packet wasn't fully received yet (still fragmented) */
  5221. -			else {
  5222. -				int sfd;/* stat server fd */
  5223. -				RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */
  5224. +int char_parsemap_fw_configstats(int fd, int id){
  5225. +	if( RFIFOREST(fd) < RFIFOW(fd,4) )
  5226. +		return 0;/* packet wasn't fully received yet (still fragmented) */
  5227. +	else {
  5228. +		int sfd;/* stat server fd */
  5229. +		RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */
  5230.  
  5231. -				if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
  5232. -					RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  5233. -					break;/* connection not possible, we drop the report */
  5234. -				}
  5235. -
  5236. -				session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
  5237. -				WFIFOHEAD(sfd, RFIFOW(fd,2) );
  5238. -				memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
  5239. -				WFIFOSET(sfd, RFIFOW(fd,2) );
  5240. -				flush_fifo(sfd);
  5241. -				do_close(sfd);
  5242. -				RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  5243. +		if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
  5244. +			RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  5245. +			return 0;/* connection not possible, we drop the report */
  5246.  		}
  5247. -		break;
  5248.  
  5249. +		session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
  5250. +		WFIFOHEAD(sfd, RFIFOW(fd,2) );
  5251. +		memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
  5252. +		WFIFOSET(sfd, RFIFOW(fd,2) );
  5253. +		flush_fifo(sfd);
  5254. +		do_close(sfd);
  5255. +		RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  5256. +	}
  5257. +	return 1;
  5258. +}
  5259. +
  5260. +int parse_frommap(int fd){
  5261. +	int id; //mapserv id
  5262. +	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  5263. +	if( id == ARRAYLENGTH(server) )
  5264. +	{// not a map server
  5265. +		ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
  5266. +		do_close(fd);
  5267. +		return 0;
  5268. +	}
  5269. +	if( session[fd]->flag.eof )
  5270. +	{
  5271. +		do_close(fd);
  5272. +		server[id].fd = -1;
  5273. +		mapif_on_disconnect(id);
  5274. +		return 0;
  5275. +	}
  5276. +
  5277. +	while(RFIFOREST(fd) >= 2){
  5278. +		switch(RFIFOW(fd,0)){
  5279. +		// Receiving map names list from the map-server
  5280. +		case 0x2afa: char_parsemap_getmapname(fd,id); break;
  5281. +		//Packet command is now used for sc_data request. [Skotlex]
  5282. +		case 0x2afc: char_parsemap_askscdata(fd,id); break;
  5283. +		//MAP user count
  5284. +		case 0x2afe: char_parsemap_getusercount(fd,id); break; //get nb user
  5285. +		case 0x2aff: char_parsemap_regmapuser(fd,id); break; //register users
  5286. +		// Receive character data from map-server for saving
  5287. +		case 0x2b01: char_parsemap_reqsavechar(fd,id); break;
  5288. +		// req char selection;
  5289. +		case 0x2b02: char_parsemap_authok(fd,id); break;
  5290. +		// request "change map server"
  5291. +		case 0x2b05: char_parsemap_reqchangemapserv(fd,id); break;
  5292. +		// Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
  5293. +		case 0x2b07: char_parsemap_askrmfriend(fd,id); break;
  5294. +		// char name request
  5295. +		case 0x2b08: char_parsemap_reqcharname(fd,id); break;
  5296. +		// Map server send information to change an email of an account -> login-server
  5297. +		case 0x2b0c: char_parsemap_reqnewemail(fd,id); break;
  5298. +		// Request from map-server to change an account's status (will just be forwarded to login server)
  5299. +		case 0x2b0e: char_parsemap_fwlog_changestatus(fd,id); break;
  5300. +		// Update and send fame ranking list
  5301. +		case 0x2b10: char_parsemap_updfamelist(fd,id); break;
  5302. +		// Divorce chars
  5303. +		case 0x2b11: char_parsemap_reqdivorce(fd,id); break;
  5304. +		// Receive rates [Wizputer]
  5305. +		case 0x2b16: char_parsemap_updmapinfo(fd,id); break;
  5306. +		// Character disconnected set online 0 [Wizputer]
  5307. +		case 0x2b17: char_parsemap_setcharoffline(fd,id); break;
  5308. +		// Reset all chars to offline [Wizputer]
  5309. +		case 0x2b18: char_parsemap_setalloffline(fd,id); break;
  5310. +		// Character set online [Wizputer]
  5311. +		case 0x2b19: char_parsemap_setcharonline(fd,id); break;
  5312. +		// Build and send fame ranking lists [DracoRPG]
  5313. +		case 0x2b1a: char_parsemap_reqfamelist(fd,id); break;
  5314. +		//Request to save status change data. [Skotlex]
  5315. +		case 0x2b1c: char_parsemap_save_scdata(fd,id); break;
  5316. +		// map-server alive packet
  5317. +		case 0x2b23: char_parsemap_keepalive(fd,id); break;
  5318. +		// auth request from map-server
  5319. +		case 0x2b26: char_parsemap_reqauth(fd,id); break;
  5320. +		// ip address update
  5321. +		case 0x2736: char_parsemap_updmapip(fd,id); break;
  5322. +		// transmit emu usage for anom stats
  5323. +		case 0x3008: char_parsemap_fw_configstats(fd,id); break;
  5324.  		default:
  5325.  		{
  5326.  			// inter server - packet
  5327.  			int r = inter_parse_frommap(fd);
  5328.  			if (r == 1) break;		// processed
  5329.  			if (r == 2) return 0;	// need more packet
  5330. -
  5331.  			// no inter server packet. no char server packet -> disconnect
  5332.  			ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
  5333.  			set_eof(fd);
  5334. @@ -3513,64 +3280,10 @@
  5335.  	return 0;
  5336.  }
  5337.  
  5338. -void do_init_mapif(void)
  5339. -{
  5340. -	int i;
  5341. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  5342. -		mapif_server_init(i);
  5343. -}
  5344. +//
  5345. +// Client IF
  5346. +//
  5347.  
  5348. -void do_final_mapif(void)
  5349. -{
  5350. -	int i;
  5351. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  5352. -		mapif_server_destroy(i);
  5353. -}
  5354. -
  5355. -// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
  5356. -// If found, returns the server's index in the 'server' array (otherwise returns -1).
  5357. -int search_mapserver(unsigned short map, uint32 ip, uint16 port)
  5358. -{
  5359. -	int i, j;
  5360. -
  5361. -	for(i = 0; i < ARRAYLENGTH(server); i++)
  5362. -	{
  5363. -		if (server[i].fd > 0
  5364. -		&& (ip == (uint32)-1 || server[i].ip == ip)
  5365. -		&& (port == (uint16)-1 || server[i].port == port))
  5366. -		{
  5367. -			for (j = 0; server[i].map[j]; j++)
  5368. -				if (server[i].map[j] == map)
  5369. -					return i;
  5370. -		}
  5371. -	}
  5372. -
  5373. -	return -1;
  5374. -}
  5375. -
  5376. -// Initialization process (currently only initialization inter_mapif)
  5377. -static int char_mapif_init(int fd)
  5378. -{
  5379. -	return inter_mapif_init(fd);
  5380. -}
  5381. -
  5382. -//--------------------------------------------
  5383. -// Test to know if an IP come from LAN or WAN.
  5384. -//--------------------------------------------
  5385. -int lan_subnetcheck(uint32 ip)
  5386. -{
  5387. -	int i;
  5388. -	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  5389. -	if( i < subnet_count ) {
  5390. -		ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask));
  5391. -		return subnet[i].map_ip;
  5392. -	} else {
  5393. -		ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
  5394. -		return 0;
  5395. -	}
  5396. -}
  5397. -
  5398. -
  5399.  /// @param result
  5400.  /// 0 (0x718): An unknown error has occurred.
  5401.  /// 1: none/success
  5402. @@ -3588,7 +3301,6 @@
  5403.  	WFIFOSET(fd,14);
  5404.  }
  5405.  
  5406. -
  5407.  /// @param result
  5408.  /// 0 (0x718): An unknown error has occurred.
  5409.  /// 1: none/success
  5410. @@ -3606,7 +3318,6 @@
  5411.  	WFIFOSET(fd,10);
  5412.  }
  5413.  
  5414. -
  5415.  /// @param result
  5416.  /// 1 (0x718): none/success, (if char id not in deletion process): An unknown error has occurred.
  5417.  /// 2 (0x719): A database error occurred.
  5418. @@ -3620,34 +3331,37 @@
  5419.  	WFIFOSET(fd,10);
  5420.  }
  5421.  
  5422. -
  5423. -static void char_delete2_req(int fd, struct char_session_data* sd)
  5424. -{// CH: <0827>.W <char id>.L
  5425. +// CH: <0827>.W <char id>.L
  5426. +int char_parse_delete2_req(int fd, struct char_session_data* sd)
  5427. +{
  5428.  	int char_id, i;
  5429.  	char* data;
  5430.  	time_t delete_date;
  5431.  
  5432. +	FIFOSD_CHECK(6)
  5433. +
  5434.  	char_id = RFIFOL(fd,2);
  5435. +	RFIFOSKIP(fd,6);
  5436.  
  5437.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  5438.  	if( i == MAX_CHARS )
  5439.  	{// character not found
  5440.  		char_delete2_ack(fd, char_id, 3, 0);
  5441. -		return;
  5442. +		return 0;
  5443.  	}
  5444.  
  5445.  	if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
  5446.  	{
  5447.  		Sql_ShowDebug(sql_handle);
  5448.  		char_delete2_ack(fd, char_id, 3, 0);
  5449. -		return;
  5450. +		return 0;
  5451.  	}
  5452.  
  5453.  	Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10);
  5454.  
  5455.  	if( delete_date ) {// character already queued for deletion
  5456.  		char_delete2_ack(fd, char_id, 0, 0);
  5457. -		return;
  5458. +		return 0;
  5459.  	}
  5460.  
  5461.  /*
  5462. @@ -3674,14 +3388,14 @@
  5463.  	{
  5464.  		Sql_ShowDebug(sql_handle);
  5465.  		char_delete2_ack(fd, char_id, 3, 0);
  5466. -		return;
  5467. +		return 0;
  5468.  	}
  5469.  
  5470.  	char_delete2_ack(fd, char_id, 1, delete_date);
  5471. +	return 1;
  5472.  }
  5473.  
  5474. -
  5475. -static void char_delete2_accept(int fd, struct char_session_data* sd)
  5476. +int char_parse_delete2_accept(int fd, struct char_session_data* sd)
  5477.  {// CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
  5478.  	char birthdate[8+1];
  5479.  	int char_id, i, k;
  5480. @@ -3689,6 +3403,8 @@
  5481.  	char* data;
  5482.  	time_t delete_date;
  5483.  
  5484. +	FIFOSD_CHECK(12)
  5485. +
  5486.  	char_id = RFIFOL(fd,2);
  5487.  
  5488.  	ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id);
  5489. @@ -3703,19 +3419,20 @@
  5490.  	birthdate[6] = RFIFOB(fd,10);
  5491.  	birthdate[7] = RFIFOB(fd,11);
  5492.  	birthdate[8] = 0;
  5493. +	RFIFOSKIP(fd,12);
  5494.  
  5495.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  5496.  	if( i == MAX_CHARS )
  5497.  	{// character not found
  5498.  		char_delete2_accept_ack(fd, char_id, 3);
  5499. -		return;
  5500. +		return 0;
  5501.  	}
  5502.  
  5503.  	if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
  5504.  	{// data error
  5505.  		Sql_ShowDebug(sql_handle);
  5506.  		char_delete2_accept_ack(fd, char_id, 3);
  5507. -		return;
  5508. +		return 0;
  5509.  	}
  5510.  
  5511.  	Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10);
  5512. @@ -3724,26 +3441,26 @@
  5513.  	if( !delete_date || delete_date>time(NULL) )
  5514.  	{// not queued or delay not yet passed
  5515.  		char_delete2_accept_ack(fd, char_id, 4);
  5516. -		return;
  5517. +		return 0;
  5518.  	}
  5519.  
  5520.  	if( strcmp(sd->birthdate+2, birthdate) )  // +2 to cut off the century
  5521.  	{// birth date is wrong
  5522.  		char_delete2_accept_ack(fd, char_id, 5);
  5523. -		return;
  5524. +		return 0;
  5525.  	}
  5526.  
  5527.  	if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) )
  5528.  	{// character level config restriction
  5529.  		char_delete2_accept_ack(fd, char_id, 2);
  5530. -		return;
  5531. +		return 0;
  5532.  	}
  5533.  
  5534.  	// success
  5535.  	if( delete_char_sql(char_id) < 0 )
  5536.  	{
  5537.  		char_delete2_accept_ack(fd, char_id, 3);
  5538. -		return;
  5539. +		return 0;
  5540.  	}
  5541.  
  5542.  	// refresh character list cache
  5543. @@ -3754,20 +3471,24 @@
  5544.  	sd->found_char[MAX_CHARS-1] = -1;
  5545.  
  5546.  	char_delete2_accept_ack(fd, char_id, 1);
  5547. +	return 1;
  5548.  }
  5549.  
  5550. -
  5551. -static void char_delete2_cancel(int fd, struct char_session_data* sd)
  5552. -{// CH: <082b>.W <char id>.L
  5553. +// CH: <082b>.W <char id>.L
  5554. +int char_parse_delete2_cancel(int fd, struct char_session_data* sd)
  5555. +{
  5556.  	int char_id, i;
  5557.  
  5558. +	FIFOSD_CHECK(6)
  5559. +
  5560.  	char_id = RFIFOL(fd,2);
  5561. +	RFIFOSKIP(fd,6);
  5562.  
  5563.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  5564.  	if( i == MAX_CHARS )
  5565.  	{// character not found
  5566.  		char_delete2_cancel_ack(fd, char_id, 2);
  5567. -		return;
  5568. +		return 0;
  5569.  	}
  5570.  
  5571.  	// there is no need to check, whether or not the character was
  5572. @@ -3777,637 +3498,52 @@
  5573.  	{
  5574.  		Sql_ShowDebug(sql_handle);
  5575.  		char_delete2_cancel_ack(fd, char_id, 2);
  5576. -		return;
  5577. +		return 0;
  5578.  	}
  5579.  
  5580.  	char_delete2_cancel_ack(fd, char_id, 1);
  5581. +	return 1;
  5582.  }
  5583.  
  5584. +int char_parse_maplogin(int fd){
  5585. +	int i;
  5586.  
  5587. -int parse_char(int fd)
  5588. -{
  5589. -	int i, ch;
  5590. -	char email[40];
  5591. -	unsigned short cmd;
  5592. -	int map_fd;
  5593. -	struct char_session_data* sd;
  5594. -	uint32 ipl = session[fd]->client_addr;
  5595. -
  5596. -	sd = (struct char_session_data*)session[fd]->session_data;
  5597. -
  5598. -	// disconnect any player if no login-server.
  5599. -	if(login_fd < 0)
  5600. -		set_eof(fd);
  5601. -
  5602. -	if(session[fd]->flag.eof)
  5603. -	{
  5604. -		if( sd != NULL && sd->auth )
  5605. -		{	// already authed client
  5606. -			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
  5607. -			if( data != NULL && data->fd == fd)
  5608. -				data->fd = -1;
  5609. -			if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
  5610. -				set_char_offline(-1,sd->account_id);
  5611. -		}
  5612. -		do_close(fd);
  5613. +	if (RFIFOREST(fd) < 60)
  5614.  		return 0;
  5615. -	}
  5616. -
  5617. -	while( RFIFOREST(fd) >= 2 )
  5618. -	{
  5619. -		//For use in packets that depend on an sd being present [Skotlex]
  5620. -		#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
  5621. -
  5622. -		cmd = RFIFOW(fd,0);
  5623. -		switch( cmd )
  5624. +	else {
  5625. +		char* l_user = (char*)RFIFOP(fd,2);
  5626. +		char* l_pass = (char*)RFIFOP(fd,26);
  5627. +		l_user[23] = '\0';
  5628. +		l_pass[23] = '\0';
  5629. +		ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
  5630. +		if( runflag != CHARSERVER_ST_RUNNING ||
  5631. +			i == ARRAYLENGTH(server) ||
  5632. +			strcmp(l_user, userid) != 0 ||
  5633. +			strcmp(l_pass, passwd) != 0 )
  5634.  		{
  5635. +			WFIFOHEAD(fd,3);
  5636. +			WFIFOW(fd,0) = 0x2af9;
  5637. +			WFIFOB(fd,2) = 3;
  5638. +			WFIFOSET(fd,3);
  5639. +		} else {
  5640. +			WFIFOHEAD(fd,3);
  5641. +			WFIFOW(fd,0) = 0x2af9;
  5642. +			WFIFOB(fd,2) = 0;
  5643. +			WFIFOSET(fd,3);
  5644.  
  5645. -		// request to connect
  5646. -		// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  5647. -		case 0x65:
  5648. -			if( RFIFOREST(fd) < 17 )
  5649. -				return 0;
  5650. -		{
  5651. -			struct auth_node* node;
  5652. -
  5653. -			int account_id = RFIFOL(fd,2);
  5654. -			uint32 login_id1 = RFIFOL(fd,6);
  5655. -			uint32 login_id2 = RFIFOL(fd,10);
  5656. -			int sex = RFIFOB(fd,16);
  5657. -			RFIFOSKIP(fd,17);
  5658. -
  5659. -			ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  5660. -
  5661. -			if (sd) {
  5662. -				//Received again auth packet for already authentified account?? Discard it.
  5663. -				//TODO: Perhaps log this as a hack attempt?
  5664. -				//TODO: and perhaps send back a reply?
  5665. -				break;
  5666. -			}
  5667. -
  5668. -			CREATE(session[fd]->session_data, struct char_session_data, 1);
  5669. -			sd = (struct char_session_data*)session[fd]->session_data;
  5670. -			sd->account_id = account_id;
  5671. -			sd->login_id1 = login_id1;
  5672. -			sd->login_id2 = login_id2;
  5673. -			sd->sex = sex;
  5674. -			sd->auth = false; // not authed yet
  5675. -
  5676. -			// send back account_id
  5677. -			WFIFOHEAD(fd,4);
  5678. -			WFIFOL(fd,0) = account_id;
  5679. -			WFIFOSET(fd,4);
  5680. -
  5681. -			if( runflag != CHARSERVER_ST_RUNNING )
  5682. -			{
  5683. -				WFIFOHEAD(fd,3);
  5684. -				WFIFOW(fd,0) = 0x6c;
  5685. -				WFIFOB(fd,2) = 0;// rejected from server
  5686. -				WFIFOSET(fd,3);
  5687. -				break;
  5688. -			}
  5689. -
  5690. -			// search authentification
  5691. -			node = (struct auth_node*)idb_get(auth_db, account_id);
  5692. -			if( node != NULL &&
  5693. -			    node->account_id == account_id &&
  5694. -				node->login_id1  == login_id1 &&
  5695. -				node->login_id2  == login_id2 /*&&
  5696. -				node->ip         == ipl*/ )
  5697. -			{// authentication found (coming from map server)
  5698. -				idb_remove(auth_db, account_id);
  5699. -				char_auth_ok(fd, sd);
  5700. -			}
  5701. -			else
  5702. -			{// authentication not found (coming from login server)
  5703. -				if (login_fd > 0) { // don't send request if no login-server
  5704. -					WFIFOHEAD(login_fd,23);
  5705. -					WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  5706. -					WFIFOL(login_fd,2) = sd->account_id;
  5707. -					WFIFOL(login_fd,6) = sd->login_id1;
  5708. -					WFIFOL(login_fd,10) = sd->login_id2;
  5709. -					WFIFOB(login_fd,14) = sd->sex;
  5710. -					WFIFOL(login_fd,15) = htonl(ipl);
  5711. -					WFIFOL(login_fd,19) = fd;
  5712. -					WFIFOSET(login_fd,23);
  5713. -				} else { // if no login-server, we must refuse connection
  5714. -					WFIFOHEAD(fd,3);
  5715. -					WFIFOW(fd,0) = 0x6c;
  5716. -					WFIFOB(fd,2) = 0;
  5717. -					WFIFOSET(fd,3);
  5718. -				}
  5719. -			}
  5720. +			server[i].fd = fd;
  5721. +			server[i].ip = ntohl(RFIFOL(fd,54));
  5722. +			server[i].port = ntohs(RFIFOW(fd,58));
  5723. +			server[i].users = 0;
  5724. +			memset(server[i].map, 0, sizeof(server[i].map));
  5725. +			session[fd]->func_parse = parse_frommap;
  5726. +			session[fd]->flag.server = 1;
  5727. +			realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  5728. +			char_mapif_init(fd);
  5729.  		}
  5730. -		break;
  5731. -
  5732. -		// char select
  5733. -		case 0x66:
  5734. -			FIFOSD_CHECK(3);
  5735. -		{
  5736. -			struct mmo_charstatus char_dat;
  5737. -			struct mmo_charstatus *cd;
  5738. -			char* data;
  5739. -			int char_id;
  5740. -			uint32 subnet_map_ip;
  5741. -			struct auth_node* node;
  5742. -
  5743. -			int slot = RFIFOB(fd,2);
  5744. -			RFIFOSKIP(fd,3);
  5745. -
  5746. -			if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot)
  5747. -			  || SQL_SUCCESS != Sql_NextRow(sql_handle)
  5748. -			  || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
  5749. -			{	//Not found?? May be forged packet.
  5750. -				Sql_ShowDebug(sql_handle);
  5751. -				Sql_FreeResult(sql_handle);
  5752. -				WFIFOHEAD(fd,3);
  5753. -				WFIFOW(fd,0) = 0x6c;
  5754. -				WFIFOB(fd,2) = 0; // rejected from server
  5755. -				WFIFOSET(fd,3);
  5756. -				break;
  5757. -			}
  5758. -
  5759. -			char_id = atoi(data);
  5760. -			Sql_FreeResult(sql_handle);
  5761. -
  5762. -			/* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  5763. -			set_char_online(-2,char_id,sd->account_id);
  5764. -			if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  5765. -				set_char_offline(char_id, sd->account_id);
  5766. -				/* failed to load something. REJECT! */
  5767. -				WFIFOHEAD(fd,3);
  5768. -				WFIFOW(fd,0) = 0x6c;
  5769. -				WFIFOB(fd,2) = 0;
  5770. -				WFIFOSET(fd,3);
  5771. -				break;/* jump off this boat */
  5772. -			}
  5773. -
  5774. -			//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  5775. -			cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
  5776. -			cd->sex = sd->sex;
  5777. -
  5778. -			if (log_char) {
  5779. -				char esc_name[NAME_LENGTH*2+1];
  5780. -
  5781. -				Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  5782. -				if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  5783. -					charlog_db, sd->account_id, slot, esc_name) )
  5784. -					Sql_ShowDebug(sql_handle);
  5785. -			}
  5786. -			ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  5787. -
  5788. -			// searching map server
  5789. -			i = search_mapserver(cd->last_point.map, -1, -1);
  5790. -
  5791. -			// if map is not found, we check major cities
  5792. -			if (i < 0 || !cd->last_point.map) {
  5793. -				unsigned short j;
  5794. -				//First check that there's actually a map server online.
  5795. -				ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
  5796. -				if (j == ARRAYLENGTH(server)) {
  5797. -					ShowInfo("Connection Closed. No map servers available.\n");
  5798. -					WFIFOHEAD(fd,3);
  5799. -					WFIFOW(fd,0) = 0x81;
  5800. -					WFIFOB(fd,2) = 1; // 01 = Server closed
  5801. -					WFIFOSET(fd,3);
  5802. -					break;
  5803. -				}
  5804. -				if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  5805. -					cd->last_point.x = 273;
  5806. -					cd->last_point.y = 354;
  5807. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  5808. -					cd->last_point.x = 120;
  5809. -					cd->last_point.y = 100;
  5810. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  5811. -					cd->last_point.x = 160;
  5812. -					cd->last_point.y = 94;
  5813. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  5814. -					cd->last_point.x = 116;
  5815. -					cd->last_point.y = 57;
  5816. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  5817. -					cd->last_point.x = 87;
  5818. -					cd->last_point.y = 117;
  5819. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  5820. -					cd->last_point.x = 94;
  5821. -					cd->last_point.y = 103;
  5822. -				} else {
  5823. -					ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
  5824. -					WFIFOHEAD(fd,3);
  5825. -					WFIFOW(fd,0) = 0x81;
  5826. -					WFIFOB(fd,2) = 1; // 01 = Server closed
  5827. -					WFIFOSET(fd,3);
  5828. -					break;
  5829. -				}
  5830. -				ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  5831. -				cd->last_point.map = j;
  5832. -			}
  5833. -
  5834. -			//Send NEW auth packet [Kevin]
  5835. -			//FIXME: is this case even possible? [ultramage]
  5836. -			if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
  5837. -			{
  5838. -				ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  5839. -				server[i].fd = -1;
  5840. -				memset(&server[i], 0, sizeof(struct mmo_map_server));
  5841. -				//Send server closed.
  5842. -				WFIFOHEAD(fd,3);
  5843. -				WFIFOW(fd,0) = 0x81;
  5844. -				WFIFOB(fd,2) = 1; // 01 = Server closed
  5845. -				WFIFOSET(fd,3);
  5846. -				break;
  5847. -			}
  5848. -
  5849. -			//Send player to map
  5850. -			WFIFOHEAD(fd,28);
  5851. -			WFIFOW(fd,0) = 0x71;
  5852. -			WFIFOL(fd,2) = cd->char_id;
  5853. -			mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
  5854. -			subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  5855. -			WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
  5856. -			WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  5857. -			WFIFOSET(fd,28);
  5858. -
  5859. -			// create temporary auth entry
  5860. -			CREATE(node, struct auth_node, 1);
  5861. -			node->account_id = sd->account_id;
  5862. -			node->char_id = cd->char_id;
  5863. -			node->login_id1 = sd->login_id1;
  5864. -			node->login_id2 = sd->login_id2;
  5865. -			node->sex = sd->sex;
  5866. -			node->expiration_time = sd->expiration_time;
  5867. -			node->group_id = sd->group_id;
  5868. -			node->ip = ipl;
  5869. -			idb_put(auth_db, sd->account_id, node);
  5870. -
  5871. -		}
  5872. -		break;
  5873. -
  5874. -		// create new char
  5875. -#if PACKETVER >= 20120307
  5876. -		// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  5877. -		case 0x970:
  5878. -			FIFOSD_CHECK(31);
  5879. -#else
  5880. -		// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  5881. -		case 0x67:
  5882. -			FIFOSD_CHECK(37);
  5883. -#endif
  5884. -
  5885. -			if( !char_new ) //turn character creation on/off [Kevin]
  5886. -				i = -2;
  5887. -			else
  5888. -#if PACKETVER >= 20120307
  5889. -				i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
  5890. -#else
  5891. -				i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
  5892. -#endif
  5893. -
  5894. -			//'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
  5895. -			if (i < 0) {
  5896. -				WFIFOHEAD(fd,3);
  5897. -				WFIFOW(fd,0) = 0x6e;
  5898. -				/* Others I found [Ind] */
  5899. -				/* 0x02 = Symbols in Character Names are forbidden */
  5900. -				/* 0x03 = You are not elegible to open the Character Slot. */
  5901. -				switch (i) {
  5902. -					case -1: WFIFOB(fd,2) = 0x00; break;
  5903. -					case -2: WFIFOB(fd,2) = 0xFF; break;
  5904. -					case -3: WFIFOB(fd,2) = 0x01; break;
  5905. -					case -4: WFIFOB(fd,2) = 0x03; break;
  5906. -				}
  5907. -				WFIFOSET(fd,3);
  5908. -			} else {
  5909. -				int len;
  5910. -				// retrieve data
  5911. -				struct mmo_charstatus char_dat;
  5912. -				mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
  5913. -
  5914. -				// send to player
  5915. -				WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  5916. -				WFIFOW(fd,0) = 0x6d;
  5917. -				len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  5918. -				WFIFOSET(fd,len);
  5919. -
  5920. -				// add new entry to the chars list
  5921. -				ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
  5922. -				if( ch < MAX_CHARS )
  5923. -					sd->found_char[ch] = i; // the char_id of the new char
  5924. -			}
  5925. -#if PACKETVER >= 20120307
  5926. -			RFIFOSKIP(fd,31);
  5927. -#else
  5928. -			RFIFOSKIP(fd,37);
  5929. -#endif
  5930. -		break;
  5931. -
  5932. -		// delete char
  5933. -		case 0x68:
  5934. -		// 2004-04-19aSakexe+ langtype 12 char deletion packet
  5935. -		case 0x1fb:
  5936. -			if (cmd == 0x68) FIFOSD_CHECK(46);
  5937. -			if (cmd == 0x1fb) FIFOSD_CHECK(56);
  5938. -		{
  5939. -			int cid = RFIFOL(fd,2);
  5940. -
  5941. -			ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
  5942. -			memcpy(email, RFIFOP(fd,6), 40);
  5943. -			RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  5944. -
  5945. -			// Check if e-mail is correct
  5946. -			if(strcmpi(email, sd->email) && //email does not matches and
  5947. -			(
  5948. -				strcmp("[email protected]", sd->email) || //it is not default email, or
  5949. -				(strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
  5950. -			)) {	//Fail
  5951. -				WFIFOHEAD(fd,3);
  5952. -				WFIFOW(fd,0) = 0x70;
  5953. -				WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
  5954. -				WFIFOSET(fd,3);
  5955. -				break;
  5956. -			}
  5957. -
  5958. -			// check if this char exists
  5959. -			ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  5960. -			if( i == MAX_CHARS )
  5961. -			{ // Such a character does not exist in the account
  5962. -				WFIFOHEAD(fd,3);
  5963. -				WFIFOW(fd,0) = 0x70;
  5964. -				WFIFOB(fd,2) = 0;
  5965. -				WFIFOSET(fd,3);
  5966. -				break;
  5967. -			}
  5968. -
  5969. -			// remove char from list and compact it
  5970. -			for(ch = i; ch < MAX_CHARS-1; ch++)
  5971. -				sd->found_char[ch] = sd->found_char[ch+1];
  5972. -			sd->found_char[MAX_CHARS-1] = -1;
  5973. -
  5974. -			/* Delete character */
  5975. -			if(delete_char_sql(cid)<0){
  5976. -				//can't delete the char
  5977. -				//either SQL error or can't delete by some CONFIG conditions
  5978. -				//del fail
  5979. -				WFIFOHEAD(fd,3);
  5980. -				WFIFOW(fd, 0) = 0x70;
  5981. -				WFIFOB(fd, 2) = 0;
  5982. -				WFIFOSET(fd, 3);
  5983. -				break;
  5984. -			}
  5985. -			/* Char successfully deleted.*/
  5986. -			WFIFOHEAD(fd,2);
  5987. -			WFIFOW(fd,0) = 0x6f;
  5988. -			WFIFOSET(fd,2);
  5989. -		}
  5990. -		break;
  5991. -
  5992. -		// client keep-alive packet (every 12 seconds)
  5993. -		// R 0187 <account ID>.l
  5994. -		case 0x187:
  5995. -			if (RFIFOREST(fd) < 6)
  5996. -				return 0;
  5997. -			RFIFOSKIP(fd,6);
  5998. -		break;
  5999. -		// char rename request
  6000. -		// R 08fc <char ID>.l <new name>.24B
  6001. -		case 0x8fc:
  6002. -			FIFOSD_CHECK(30);
  6003. -			{
  6004. -				int i, cid =RFIFOL(fd,2);
  6005. -				char name[NAME_LENGTH];
  6006. -				char esc_name[NAME_LENGTH*2+1];
  6007. -				safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH);
  6008. -				RFIFOSKIP(fd,30);
  6009. -
  6010. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  6011. -				if( i == MAX_CHARS )
  6012. -					break;
  6013. -
  6014. -				normalize_name(name,TRIM_CHARS);
  6015. -				Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  6016. -				if( !check_char_name(name,esc_name) ) {
  6017. -					i = 1;
  6018. -					safestrncpy(sd->new_name, name, NAME_LENGTH);
  6019. -				} else
  6020. -					i = 0;
  6021. -
  6022. -				WFIFOHEAD(fd, 4);
  6023. -				WFIFOW(fd,0) = 0x28e;
  6024. -				WFIFOW(fd,2) = i;
  6025. -				WFIFOSET(fd,4);
  6026. -			}
  6027. -			break;
  6028. -
  6029. -		// char rename request
  6030. -		// R 028d <account ID>.l <char ID>.l <new name>.24B
  6031. -		case 0x28d:
  6032. -			FIFOSD_CHECK(34);
  6033. -			{
  6034. -				int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6);
  6035. -				char name[NAME_LENGTH];
  6036. - 				char esc_name[NAME_LENGTH*2+1];
  6037. -				safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
  6038. -				RFIFOSKIP(fd,34);
  6039. -
  6040. -				if( aid != sd->account_id )
  6041. -					break;
  6042. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  6043. -				if( i == MAX_CHARS )
  6044. -					break;
  6045. -
  6046. -				normalize_name(name,TRIM_CHARS);
  6047. -				Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  6048. -				if( !check_char_name(name,esc_name) )
  6049. -				{
  6050. -					i = 1;
  6051. -					safestrncpy(sd->new_name, name, NAME_LENGTH);
  6052. -				}
  6053. -				else
  6054. -					i = 0;
  6055. -
  6056. -				WFIFOHEAD(fd, 4);
  6057. -				WFIFOW(fd,0) = 0x28e;
  6058. -				WFIFOW(fd,2) = i;
  6059. -				WFIFOSET(fd,4);
  6060. -			}
  6061. -			break;
  6062. -		//Confirm change name.
  6063. -		// 0x28f <char_id>.L
  6064. -		case 0x28f:
  6065. -			// 0: Sucessfull
  6066. -			// 1: This character's name has already been changed. You cannot change a character's name more than once.
  6067. -			// 2: User information is not correct.
  6068. -			// 3: You have failed to change this character's name.
  6069. -			// 4: Another user is using this character name, so please select another one.
  6070. -			FIFOSD_CHECK(6);
  6071. -			{
  6072. -				int i;
  6073. -				int cid = RFIFOL(fd,2);
  6074. -				RFIFOSKIP(fd,6);
  6075. -
  6076. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  6077. -				if( i == MAX_CHARS )
  6078. -					break;
  6079. -				i = rename_char_sql(sd, cid);
  6080. -
  6081. -				WFIFOHEAD(fd, 4);
  6082. -				WFIFOW(fd,0) = 0x290;
  6083. -				WFIFOW(fd,2) = i;
  6084. -				WFIFOSET(fd,4);
  6085. -			}
  6086. -			break;
  6087. -
  6088. -		// captcha code request (not implemented)
  6089. -		// R 07e5 <?>.w <aid>.l
  6090. -		case 0x7e5:
  6091. -			WFIFOHEAD(fd,5);
  6092. -			WFIFOW(fd,0) = 0x7e9;
  6093. -			WFIFOW(fd,2) = 5;
  6094. -			WFIFOB(fd,4) = 1;
  6095. -			WFIFOSET(fd,5);
  6096. -			RFIFOSKIP(fd,8);
  6097. -			break;
  6098. -
  6099. -		// captcha code check (not implemented)
  6100. -		// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  6101. -		case 0x7e7:
  6102. -			WFIFOHEAD(fd,5);
  6103. -			WFIFOW(fd,0) = 0x7e9;
  6104. -			WFIFOW(fd,2) = 5;
  6105. -			WFIFOB(fd,4) = 1;
  6106. -			WFIFOSET(fd,5);
  6107. -			RFIFOSKIP(fd,32);
  6108. -		break;
  6109. -
  6110. -		// deletion timer request
  6111. -		case 0x827:
  6112. -			FIFOSD_CHECK(6);
  6113. -			char_delete2_req(fd, sd);
  6114. -			RFIFOSKIP(fd,6);
  6115. -		break;
  6116. -
  6117. -		// deletion accept request
  6118. -		case 0x829:
  6119. -			FIFOSD_CHECK(12);
  6120. -			char_delete2_accept(fd, sd);
  6121. -			RFIFOSKIP(fd,12);
  6122. -		break;
  6123. -
  6124. -		// deletion cancel request
  6125. -		case 0x82b:
  6126. -			FIFOSD_CHECK(6);
  6127. -			char_delete2_cancel(fd, sd);
  6128. -			RFIFOSKIP(fd,6);
  6129. -		break;
  6130. -
  6131. -		// login as map-server
  6132. -		case 0x2af8:
  6133. -			if (RFIFOREST(fd) < 60)
  6134. -				return 0;
  6135. -			else {
  6136. -				char* l_user = (char*)RFIFOP(fd,2);
  6137. -				char* l_pass = (char*)RFIFOP(fd,26);
  6138. -				l_user[23] = '\0';
  6139. -				l_pass[23] = '\0';
  6140. -				ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
  6141. -				if( runflag != CHARSERVER_ST_RUNNING ||
  6142. -					i == ARRAYLENGTH(server) ||
  6143. -					strcmp(l_user, userid) != 0 ||
  6144. -					strcmp(l_pass, passwd) != 0 )
  6145. -				{
  6146. -					WFIFOHEAD(fd,3);
  6147. -					WFIFOW(fd,0) = 0x2af9;
  6148. -					WFIFOB(fd,2) = 3;
  6149. -					WFIFOSET(fd,3);
  6150. -				} else {
  6151. -					WFIFOHEAD(fd,3);
  6152. -					WFIFOW(fd,0) = 0x2af9;
  6153. -					WFIFOB(fd,2) = 0;
  6154. -					WFIFOSET(fd,3);
  6155. -
  6156. -					server[i].fd = fd;
  6157. -					server[i].ip = ntohl(RFIFOL(fd,54));
  6158. -					server[i].port = ntohs(RFIFOW(fd,58));
  6159. -					server[i].users = 0;
  6160. -					memset(server[i].map, 0, sizeof(server[i].map));
  6161. -					session[fd]->func_parse = parse_frommap;
  6162. -					session[fd]->flag.server = 1;
  6163. -					realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  6164. -					char_mapif_init(fd);
  6165. -				}
  6166. -				RFIFOSKIP(fd,60);
  6167. -			}
  6168. -			return 0; // avoid processing of followup packets here
  6169. -
  6170. -		// checks the entered pin
  6171. -		case 0x8b8:
  6172. -			if( RFIFOREST(fd) < 10 )
  6173. -				return 0;
  6174. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  6175. -				pincode_check( fd, sd );
  6176. -			RFIFOSKIP(fd,10);
  6177. -		break;
  6178. -
  6179. -		// request for PIN window
  6180. -		case 0x8c5:
  6181. -			if( RFIFOREST(fd) < 6 )
  6182. -				return 0;
  6183. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  6184. -				if( strlen( sd->pincode ) <= 0 ){
  6185. -					pincode_sendstate( fd, sd, PINCODE_NEW );
  6186. -				}else{
  6187. -					pincode_sendstate( fd, sd, PINCODE_ASK );
  6188. -				}
  6189. -			}
  6190. -			RFIFOSKIP(fd,6);
  6191. -		break;
  6192. -
  6193. -		// pincode change request
  6194. -		case 0x8be:
  6195. -			if( RFIFOREST(fd) < 14 )
  6196. -				return 0;
  6197. -
  6198. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  6199. -				pincode_change( fd, sd );
  6200. -
  6201. -			RFIFOSKIP(fd,14);
  6202. -		break;
  6203. -
  6204. -		// activate PIN system and set first PIN
  6205. -		case 0x8ba:
  6206. -			if( RFIFOREST(fd) < 10 )
  6207. -				return 0;
  6208. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  6209. -				pincode_setnew( fd, sd );
  6210. -			RFIFOSKIP(fd,10);
  6211. -		break;
  6212. -
  6213. -		// character movement request
  6214. -		case 0x8d4:
  6215. -			if( RFIFOREST(fd) < 8 )
  6216. -				return 0;
  6217. -
  6218. -			moveCharSlot( fd, sd, RFIFOW(fd, 2), RFIFOW(fd, 4) );
  6219. -			mmo_char_send(fd, sd);
  6220. -			RFIFOSKIP(fd,8);
  6221. -		break;
  6222. -
  6223. -		case 0x9a1:
  6224. -			if( RFIFOREST(fd) < 2 )
  6225. -				return 0;
  6226. -			char_parse_req_charlist(fd,sd);
  6227. -			RFIFOSKIP(fd,2);
  6228. -			break;
  6229. -
  6230. -		// unknown packet received
  6231. -		default:
  6232. -			ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL));
  6233. -			set_eof(fd);
  6234. -			return 0;
  6235. -		}
  6236. +		RFIFOSKIP(fd,60);
  6237.  	}
  6238. -
  6239. -	RFIFOFLUSH(fd);
  6240. -	return 0;
  6241. +	return 1;
  6242.  }
  6243.  
  6244.  // Console Command Parser [Wizputer]
  6245. @@ -4563,53 +3699,84 @@
  6246.  	return 0;
  6247.  }
  6248.  
  6249. -int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
  6250. -{
  6251. -	if (login_fd > 0 && session[login_fd] != NULL)
  6252. -		return 0;
  6253. +//------------------------------------------------
  6254. +//Pincode system
  6255. +//------------------------------------------------
  6256.  
  6257. -	ShowInfo("Attempt to connect to login-server...\n");
  6258. -	login_fd = make_connection(login_ip, login_port, false,10);
  6259. -	if (login_fd == -1)
  6260. -	{	//Try again later. [Skotlex]
  6261. -		login_fd = 0;
  6262. +/* pincode_sendstate transmist the pincode state to client
  6263. + * S 08b9 <seed>.L <aid>.L <state>.W (HC_SECOND_PASSWD_LOGIN)
  6264. + * state :
  6265. + *   0 = disabled / pin is correct
  6266. + *   1 = ask for pin - client sends 0x8b8
  6267. + *   2 = create new pin - client sends 0x8ba
  6268. + *   3 = pin must be changed - client 0x8be
  6269. + *   4 = create new pin - client sends 0x8ba
  6270. + *   5 = client shows msgstr(1896)
  6271. + *   6 = client shows msgstr(1897) Unable to use your KSSN number
  6272. + *   7 = char select window shows a button - client sends 0x8c5
  6273. + *   8 = pincode was incorrect
  6274. +*/
  6275. +void pincode_sendstate( int fd, struct char_session_data* sd, enum pincode_state state ){
  6276. +	WFIFOHEAD(fd, 12);
  6277. +	WFIFOW(fd, 0) = 0x8b9;
  6278. +	WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  6279. +	WFIFOL(fd, 6) = sd->account_id;
  6280. +	WFIFOW(fd,10) = state;
  6281. +	WFIFOSET(fd,12);
  6282. +}
  6283. +
  6284. +void pincode_notifyLoginPinError( int account_id ){
  6285. +	WFIFOHEAD(login_fd,6);
  6286. +	WFIFOW(login_fd,0) = 0x2739;
  6287. +	WFIFOL(login_fd,2) = account_id;
  6288. +	WFIFOSET(login_fd,6);
  6289. +}
  6290. +
  6291. +void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
  6292. +	WFIFOHEAD(login_fd,11);
  6293. +	WFIFOW(login_fd,0) = 0x2738;
  6294. +	WFIFOL(login_fd,2) = account_id;
  6295. +	strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
  6296. +	WFIFOSET(login_fd,11);
  6297. +}
  6298. +
  6299. +int char_parse_reqpincode_window(int fd, struct char_session_data* sd){
  6300. +	if( RFIFOREST(fd) < 6 )
  6301.  		return 0;
  6302. +	if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  6303. +		if( strlen( sd->pincode ) <= 0 ){
  6304. +			pincode_sendstate( fd, sd, PINCODE_NEW );
  6305. +		}else{
  6306. +			pincode_sendstate( fd, sd, PINCODE_ASK );
  6307. +		}
  6308.  	}
  6309. -	session[login_fd]->func_parse = parse_fromlogin;
  6310. -	session[login_fd]->flag.server = 1;
  6311. -	realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  6312. -
  6313. -	WFIFOHEAD(login_fd,86);
  6314. -	WFIFOW(login_fd,0) = 0x2710;
  6315. -	memcpy(WFIFOP(login_fd,2), userid, 24);
  6316. -	memcpy(WFIFOP(login_fd,26), passwd, 24);
  6317. -	WFIFOL(login_fd,50) = 0;
  6318. -	WFIFOL(login_fd,54) = htonl(char_ip);
  6319. -	WFIFOW(login_fd,58) = htons(char_port);
  6320. -	memcpy(WFIFOP(login_fd,60), server_name, 20);
  6321. -	WFIFOW(login_fd,80) = 0;
  6322. -	WFIFOW(login_fd,82) = char_maintenance;
  6323. -	WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
  6324. -	WFIFOSET(login_fd,86);
  6325. -
  6326. +	RFIFOSKIP(fd,6);
  6327.  	return 1;
  6328.  }
  6329.  
  6330. -//------------------------------------------------
  6331. -//Pincode system
  6332. -//------------------------------------------------
  6333. -void pincode_check( int fd, struct char_session_data* sd ){
  6334. -	char pin[PINCODE_LENGTH+1];
  6335. +void pincode_decrypt( uint32 userSeed, char* pin ){
  6336. +	int i, pos;
  6337. +	char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  6338. +	char *buf;
  6339. +	uint32 multiplier = 0x3498, baseSeed = 0x881234;
  6340.  
  6341. -	memset(pin,0,PINCODE_LENGTH+1);
  6342. +	for( i = 1; i < 10; i++ ){
  6343. +		userSeed = baseSeed + userSeed * multiplier;
  6344. +		pos = userSeed % ( i + 1 );
  6345. +		if( i != pos ){
  6346. +			tab[i] ^= tab[pos];
  6347. +			tab[pos] ^= tab[i];
  6348. +			tab[i] ^= tab[pos];
  6349. +		}
  6350. +	}
  6351.  
  6352. -	strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
  6353. -
  6354. -	pincode_decrypt(sd->pincode_seed, pin );
  6355. -
  6356. -	if( pincode_compare( fd, sd, pin ) ){
  6357. -		pincode_sendstate( fd, sd, PINCODE_PASSED );
  6358. +	buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
  6359. +	memset( buf, 0, PINCODE_LENGTH + 1 );
  6360. +	for( i = 0; i < PINCODE_LENGTH; i++ ){
  6361. +		sprintf( buf + i, "%d", tab[pin[i] - '0'] );
  6362.  	}
  6363. +	strcpy( pin, buf );
  6364. +	free( buf );
  6365.  }
  6366.  
  6367.  int pincode_compare( int fd, struct char_session_data* sd, char* pin ){
  6368. @@ -4627,114 +3794,110 @@
  6369.  	}
  6370.  }
  6371.  
  6372. -void pincode_change( int fd, struct char_session_data* sd ){
  6373. +int char_parse_pincode_check( int fd, struct char_session_data* sd ){
  6374. +	char pin[PINCODE_LENGTH+1];
  6375. +
  6376. +	if( RFIFOREST(fd) < 10 )
  6377. +		return 0;
  6378. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  6379. +		return 0;
  6380. +
  6381. +	memset(pin,0,PINCODE_LENGTH+1);
  6382. +	strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
  6383. +	RFIFOSKIP(fd,10);
  6384. +
  6385. +	pincode_decrypt(sd->pincode_seed, pin );
  6386. +	if( pincode_compare( fd, sd, pin ) ){
  6387. +		pincode_sendstate( fd, sd, PINCODE_PASSED );
  6388. +	}
  6389. +	return 1;
  6390. +}
  6391. +
  6392. +int char_parse_pincode_change( int fd, struct char_session_data* sd ){
  6393.  	char oldpin[PINCODE_LENGTH+1];
  6394.  	char newpin[PINCODE_LENGTH+1];
  6395.  
  6396. +	if( RFIFOREST(fd) < 14 )
  6397. +		return 0;
  6398. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  6399. +		return 0;
  6400. +
  6401.  	memset(oldpin,0,PINCODE_LENGTH+1);
  6402.  	memset(newpin,0,PINCODE_LENGTH+1);
  6403. +	strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
  6404. +	strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
  6405. +	RFIFOSKIP(fd,14);
  6406.  
  6407. -	strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
  6408.  	pincode_decrypt(sd->pincode_seed,oldpin);
  6409. -
  6410.  	if( !pincode_compare( fd, sd, oldpin ) )
  6411. -		return;
  6412. -
  6413. -	strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
  6414. +		return 0;
  6415.  	pincode_decrypt(sd->pincode_seed,newpin);
  6416.  
  6417.  	pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  6418.  	strncpy(sd->pincode, newpin, sizeof(newpin));
  6419.  
  6420.  	pincode_sendstate( fd, sd, PINCODE_PASSED );
  6421. +	return 1;
  6422.  }
  6423.  
  6424. -void pincode_setnew( int fd, struct char_session_data* sd ){
  6425. +int char_parse_pincode_setnew( int fd, struct char_session_data* sd ){
  6426.  	char newpin[PINCODE_LENGTH+1];
  6427.  
  6428.  	memset(newpin,0,PINCODE_LENGTH+1);
  6429.  
  6430. +	if( RFIFOREST(fd) < 10 )
  6431. +		return 0;
  6432. +
  6433. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  6434. +		return 0;
  6435.  	strncpy( newpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH );
  6436. +	RFIFOSKIP(fd,10);
  6437. +
  6438.  	pincode_decrypt( sd->pincode_seed, newpin );
  6439.  
  6440.  	pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  6441.  	strncpy( sd->pincode, newpin, strlen( newpin ) );
  6442.  
  6443.  	pincode_sendstate( fd, sd, PINCODE_PASSED );
  6444. +	return 1;
  6445.  }
  6446.  
  6447. -// 0 = disabled / pin is correct
  6448. -// 1 = ask for pin - client sends 0x8b8
  6449. -// 2 = create new pin - client sends 0x8ba
  6450. -// 3 = pin must be changed - client 0x8be
  6451. -// 4 = create new pin - client sends 0x8ba
  6452. -// 5 = client shows msgstr(1896)
  6453. -// 6 = client shows msgstr(1897) Unable to use your KSSN number
  6454. -// 7 = char select window shows a button - client sends 0x8c5
  6455. -// 8 = pincode was incorrect
  6456. -void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state ){
  6457. -	WFIFOHEAD(fd, 12);
  6458. -	WFIFOW(fd, 0) = 0x8b9;
  6459. -	WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  6460. -	WFIFOL(fd, 6) = sd->account_id;
  6461. -	WFIFOW(fd,10) = state;
  6462. -	WFIFOSET(fd,12);
  6463. -}
  6464.  
  6465. -void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
  6466. -	WFIFOHEAD(login_fd,11);
  6467. -	WFIFOW(login_fd,0) = 0x2738;
  6468. -	WFIFOL(login_fd,2) = account_id;
  6469. -	strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
  6470. -	WFIFOSET(login_fd,11);
  6471. +//------------------------------------------------
  6472. +//Add On system
  6473. +//------------------------------------------------
  6474. +// reason
  6475. +// 0: success
  6476. +// 1: failed
  6477. +void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  6478. +	WFIFOHEAD(fd,8);
  6479. +	WFIFOW(fd,0) = 0x8d5;
  6480. +	WFIFOW(fd,2) = 8;
  6481. +	WFIFOW(fd,4) = reason;
  6482. +	WFIFOW(fd,6) = sd->char_moves[index];
  6483. +	WFIFOSET(fd,8);
  6484.  }
  6485.  
  6486. -void pincode_notifyLoginPinError( int account_id ){
  6487. -	WFIFOHEAD(login_fd,6);
  6488. -	WFIFOW(login_fd,0) = 0x2739;
  6489. -	WFIFOL(login_fd,2) = account_id;
  6490. -	WFIFOSET(login_fd,6);
  6491. -}
  6492. +int char_parse_moveCharSlot( int fd, struct char_session_data* sd){
  6493. +	uint16 from, to;
  6494.  
  6495. -void pincode_decrypt( uint32 userSeed, char* pin ){
  6496. -	int i, pos;
  6497. -	char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  6498. -	char *buf;
  6499. -	uint32 multiplier = 0x3498, baseSeed = 0x881234;
  6500. +	if( RFIFOREST(fd) < 8 )
  6501. +		return 0;
  6502. +	from = RFIFOW(fd,2);
  6503. +	to = RFIFOW(fd,4);
  6504. +	//Cnt = RFIFOW(fd,6); //how many time we have left to change (client.. lol we don't trust him)
  6505. +	RFIFOSKIP(fd,8);
  6506.  
  6507. -	for( i = 1; i < 10; i++ ){
  6508. -		userSeed = baseSeed + userSeed * multiplier;
  6509. -		pos = userSeed % ( i + 1 );
  6510. -		if( i != pos ){
  6511. -			tab[i] ^= tab[pos];
  6512. -			tab[pos] ^= tab[i];
  6513. -			tab[i] ^= tab[pos];
  6514. -		}
  6515. -	}
  6516. -
  6517. -	buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
  6518. -	memset( buf, 0, PINCODE_LENGTH + 1 );
  6519. -	for( i = 0; i < PINCODE_LENGTH; i++ ){
  6520. -		sprintf( buf + i, "%d", tab[pin[i] - '0'] );
  6521. -	}
  6522. -	strcpy( pin, buf );
  6523. -	free( buf );
  6524. -}
  6525. -
  6526. -//------------------------------------------------
  6527. -//Add On system
  6528. -//------------------------------------------------
  6529. -void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to ){
  6530.  	// Have we changed to often or is it disabled?
  6531.  	if( !char_move_enabled || ( !char_moves_unlimited && sd->char_moves[from] <= 0 ) ){
  6532.  		moveCharSlotReply( fd, sd, from, 1 );
  6533. -		return;
  6534. +		return 0;
  6535.  	}
  6536.  
  6537.  	// We dont even have a character on the chosen slot?
  6538.  	if( sd->found_char[from] <= 0 ){
  6539.  		moveCharSlotReply( fd, sd, from, 1 );
  6540. -		return;
  6541. +		return 0;
  6542.  	}
  6543.  
  6544.  	if( sd->found_char[to] > 0 ){
  6545. @@ -4749,17 +3912,17 @@
  6546.  				moveCharSlotReply( fd, sd, from, 1 );
  6547.  				Sql_ShowDebug(sql_handle);
  6548.  				Sql_QueryStr(sql_handle,"ROLLBACK");
  6549. -				return;
  6550. +				return 0;
  6551.  			}
  6552.  		}else{
  6553.  			// Admin doesnt allow us to
  6554.  			moveCharSlotReply( fd, sd, from, 1 );
  6555. -			return;
  6556. +			return 0;
  6557.  		}
  6558.  	}else if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id`='%d'", char_db, to, sd->found_char[from] ) ){
  6559.  		Sql_ShowDebug(sql_handle);
  6560.  		moveCharSlotReply( fd, sd, from, 1 );
  6561. -		return;
  6562. +		return 0;
  6563.  	}
  6564.  
  6565.  	if( !char_moves_unlimited ){
  6566. @@ -4770,20 +3933,9 @@
  6567.  	// We successfully moved the char - time to notify the client
  6568.  	moveCharSlotReply( fd, sd, from, 0 );
  6569.  	mmo_char_send(fd, sd);
  6570. +	return 1;
  6571.  }
  6572.  
  6573. -// reason
  6574. -// 0: success
  6575. -// 1: failed
  6576. -void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  6577. -	WFIFOHEAD(fd,8);
  6578. -	WFIFOW(fd,0) = 0x8d5;
  6579. -	WFIFOW(fd,2) = 8;
  6580. -	WFIFOW(fd,4) = reason;
  6581. -	WFIFOW(fd,6) = sd->char_moves[index];
  6582. -	WFIFOSET(fd,8);
  6583. -}
  6584. -
  6585.  //------------------------------------------------
  6586.  //Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
  6587.  //replies/disconnect the player we tried to kick. [Skotlex]
  6588. @@ -5154,6 +4306,980 @@
  6589.  	return 0;
  6590.  }
  6591.  
  6592. +
  6593. +
  6594. +// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  6595. +int char_parse_reqtoconnect(int fd, struct char_session_data* sd,uint32 ipl){
  6596. +	if( RFIFOREST(fd) < 17 ) // request to connect
  6597. +		return 0;
  6598. +	else {
  6599. +		struct auth_node* node;
  6600. +
  6601. +		int account_id = RFIFOL(fd,2);
  6602. +		uint32 login_id1 = RFIFOL(fd,6);
  6603. +		uint32 login_id2 = RFIFOL(fd,10);
  6604. +		int sex = RFIFOB(fd,16);
  6605. +		RFIFOSKIP(fd,17);
  6606. +
  6607. +		ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  6608. +
  6609. +		if (sd) {
  6610. +			//Received again auth packet for already authentified account?? Discard it.
  6611. +			//TODO: Perhaps log this as a hack attempt?
  6612. +			//TODO: and perhaps send back a reply?
  6613. +			ShowInfo("Already registered break\n");
  6614. +			return 0;
  6615. +		}
  6616. +
  6617. +		CREATE(session[fd]->session_data, struct char_session_data, 1);
  6618. +		sd = (struct char_session_data*)session[fd]->session_data;
  6619. +		sd->account_id = account_id;
  6620. +		sd->login_id1 = login_id1;
  6621. +		sd->login_id2 = login_id2;
  6622. +		sd->sex = sex;
  6623. +		sd->auth = false; // not authed yet
  6624. +
  6625. +		// send back account_id
  6626. +		WFIFOHEAD(fd,4);
  6627. +		WFIFOL(fd,0) = account_id;
  6628. +		WFIFOSET(fd,4);
  6629. +
  6630. +		if( runflag != CHARSERVER_ST_RUNNING )
  6631. +		{
  6632. +			WFIFOHEAD(fd,3);
  6633. +			WFIFOW(fd,0) = 0x6c;
  6634. +			WFIFOB(fd,2) = 0;// rejected from server
  6635. +			WFIFOSET(fd,3);
  6636. +			return 0;
  6637. +		}
  6638. +
  6639. +		// search authentification
  6640. +		node = (struct auth_node*)idb_get(auth_db, account_id);
  6641. +		if( node != NULL &&
  6642. +		    node->account_id == account_id &&
  6643. +			node->login_id1  == login_id1 &&
  6644. +			node->login_id2  == login_id2 /*&&
  6645. +			node->ip         == ipl*/ )
  6646. +		{// authentication found (coming from map server)
  6647. +			struct online_char_data* ol_cd = (struct online_char_data*)idb_get(online_char_db, account_id);
  6648. +			if(ol_cd) sd->version = ol_cd->version;
  6649. +			ShowInfo("char_parse_reqtoconnect: authentication found (coming from map server), sd->v=%d online_chd=%d\n",sd->version,ol_cd);
  6650. +			idb_remove(auth_db, account_id);
  6651. +			char_auth_ok(fd, sd);
  6652. +		}
  6653. +		else
  6654. +		{// authentication not found (coming from login server)
  6655. +			if (login_fd > 0) { // don't send request if no login-server
  6656. +				WFIFOHEAD(login_fd,23);
  6657. +				WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  6658. +				WFIFOL(login_fd,2) = sd->account_id;
  6659. +				WFIFOL(login_fd,6) = sd->login_id1;
  6660. +				WFIFOL(login_fd,10) = sd->login_id2;
  6661. +				WFIFOB(login_fd,14) = sd->sex;
  6662. +				WFIFOL(login_fd,15) = htonl(ipl);
  6663. +				WFIFOL(login_fd,19) = fd;
  6664. +				WFIFOSET(login_fd,23);
  6665. +			} else { // if no login-server, we must refuse connection
  6666. +				WFIFOHEAD(fd,3);
  6667. +				WFIFOW(fd,0) = 0x6c;
  6668. +				WFIFOB(fd,2) = 0;
  6669. +				WFIFOSET(fd,3);
  6670. +			}
  6671. +		}
  6672. +	}
  6673. +	return 1;
  6674. +}
  6675. +
  6676. +int char_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
  6677. +	FIFOSD_CHECK(3);
  6678. +	{
  6679. +		struct mmo_charstatus char_dat;
  6680. +		struct mmo_charstatus *cd;
  6681. +		char* data;
  6682. +		int char_id;
  6683. +		uint32 subnet_map_ip;
  6684. +		struct auth_node* node;
  6685. +		int i, map_fd;
  6686. +
  6687. +		int slot = RFIFOB(fd,2);
  6688. +		RFIFOSKIP(fd,3);
  6689. +
  6690. +		if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot)
  6691. +		  || SQL_SUCCESS != Sql_NextRow(sql_handle)
  6692. +		  || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
  6693. +		{	//Not found?? May be forged packet.
  6694. +			Sql_ShowDebug(sql_handle);
  6695. +			Sql_FreeResult(sql_handle);
  6696. +			WFIFOHEAD(fd,3);
  6697. +			WFIFOW(fd,0) = 0x6c;
  6698. +			WFIFOB(fd,2) = 0; // rejected from server
  6699. +			WFIFOSET(fd,3);
  6700. +			return 0;
  6701. +		}
  6702. +
  6703. +		char_id = atoi(data);
  6704. +		Sql_FreeResult(sql_handle);
  6705. +
  6706. +		/* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  6707. +		set_char_online(-2,char_id,sd->account_id);
  6708. +		if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  6709. +			set_char_offline(char_id, sd->account_id);
  6710. +			/* failed to load something. REJECT! */
  6711. +			WFIFOHEAD(fd,3);
  6712. +			WFIFOW(fd,0) = 0x6c;
  6713. +			WFIFOB(fd,2) = 0;
  6714. +			WFIFOSET(fd,3);
  6715. +			return 0;/* jump off this boat */
  6716. +		}
  6717. +
  6718. +		//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  6719. +		cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
  6720. +		cd->sex = sd->sex;
  6721. +
  6722. +		if (log_char) {
  6723. +			char esc_name[NAME_LENGTH*2+1];
  6724. +
  6725. +			Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  6726. +			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  6727. +				charlog_db, sd->account_id, slot, esc_name) )
  6728. +				Sql_ShowDebug(sql_handle);
  6729. +		}
  6730. +		ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  6731. +
  6732. +		// searching map server
  6733. +		i = search_mapserver(cd->last_point.map, -1, -1);
  6734. +
  6735. +		// if map is not found, we check major cities
  6736. +		if (i < 0 || !cd->last_point.map) {
  6737. +			unsigned short j;
  6738. +			//First check that there's actually a map server online.
  6739. +			ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
  6740. +			if (j == ARRAYLENGTH(server)) {
  6741. +				ShowInfo("Connection Closed. No map servers available.\n");
  6742. +				char_send_auth_result(fd,1); // 01 = Server closed
  6743. +				return 0;
  6744. +			}
  6745. +			if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  6746. +				cd->last_point.x = 273;
  6747. +				cd->last_point.y = 354;
  6748. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  6749. +				cd->last_point.x = 120;
  6750. +				cd->last_point.y = 100;
  6751. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  6752. +				cd->last_point.x = 160;
  6753. +				cd->last_point.y = 94;
  6754. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  6755. +				cd->last_point.x = 116;
  6756. +				cd->last_point.y = 57;
  6757. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  6758. +				cd->last_point.x = 87;
  6759. +				cd->last_point.y = 117;
  6760. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  6761. +				cd->last_point.x = 94;
  6762. +				cd->last_point.y = 103;
  6763. +			} else {
  6764. +				ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
  6765. +				char_send_auth_result(fd,1); // 01 = Server closed
  6766. +				return 0;
  6767. +			}
  6768. +			ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  6769. +			cd->last_point.map = j;
  6770. +		}
  6771. +
  6772. +		//Send NEW auth packet [Kevin]
  6773. +		//FIXME: is this case even possible? [ultramage]
  6774. +		if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
  6775. +		{
  6776. +			ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  6777. +			server[i].fd = -1;
  6778. +			memset(&server[i], 0, sizeof(struct mmo_map_server));
  6779. +			char_send_auth_result(fd,1);  //Send server closed.
  6780. +			return 0;
  6781. +		}
  6782. +
  6783. +		//Send player to map
  6784. +		WFIFOHEAD(fd,28);
  6785. +		WFIFOW(fd,0) = 0x71;
  6786. +		WFIFOL(fd,2) = cd->char_id;
  6787. +		mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
  6788. +		subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  6789. +		WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
  6790. +		WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  6791. +		WFIFOSET(fd,28);
  6792. +
  6793. +		// create temporary auth entry
  6794. +		CREATE(node, struct auth_node, 1);
  6795. +		node->account_id = sd->account_id;
  6796. +		node->char_id = cd->char_id;
  6797. +		node->login_id1 = sd->login_id1;
  6798. +		node->login_id2 = sd->login_id2;
  6799. +		node->sex = sd->sex;
  6800. +		node->expiration_time = sd->expiration_time;
  6801. +		node->group_id = sd->group_id;
  6802. +		node->ip = ipl;
  6803. +		idb_put(auth_db, sd->account_id, node);
  6804. +
  6805. +	}
  6806. +	return 1;
  6807. +}
  6808. +
  6809. +// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  6810. +// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  6811. +int char_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
  6812. +	int i=0, ch;
  6813. +
  6814. +	if (cmd == 0x970) FIFOSD_CHECK(31) //>=20120307
  6815. +	else if (cmd == 0x67) FIFOSD_CHECK(37)
  6816. +	else return 0;
  6817. +
  6818. +	if( !char_new ) //turn character creation on/off [Kevin]
  6819. +		i = -2;
  6820. +	else {
  6821. +		if (cmd == 0x970){
  6822. +			i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
  6823. +			RFIFOSKIP(fd,31);
  6824. +		}
  6825. +		else if(cmd == 0x67){
  6826. +#if PACKETVER < 20120307
  6827. +			i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
  6828. +			RFIFOSKIP(fd,37);
  6829. +#endif
  6830. +		}
  6831. +	}
  6832. +
  6833. +	//'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
  6834. +	if (i < 0) {
  6835. +		WFIFOHEAD(fd,3);
  6836. +		WFIFOW(fd,0) = 0x6e;
  6837. +		/* Others I found [Ind] */
  6838. +		/* 0x02 = Symbols in Character Names are forbidden */
  6839. +		/* 0x03 = You are not elegible to open the Character Slot. */
  6840. +		switch (i) {
  6841. +			case -1: WFIFOB(fd,2) = 0x00; break;
  6842. +			case -2: WFIFOB(fd,2) = 0xFF; break;
  6843. +			case -3: WFIFOB(fd,2) = 0x01; break;
  6844. +			case -4: WFIFOB(fd,2) = 0x03; break;
  6845. +		}
  6846. +		WFIFOSET(fd,3);
  6847. +	} else {
  6848. +		int len;
  6849. +		// retrieve data
  6850. +		struct mmo_charstatus char_dat;
  6851. +		mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
  6852. +
  6853. +		// send to player
  6854. +		WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  6855. +		WFIFOW(fd,0) = 0x6d;
  6856. +		len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  6857. +		WFIFOSET(fd,len);
  6858. +
  6859. +		// add new entry to the chars list
  6860. +		ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
  6861. +		if( ch < MAX_CHARS )
  6862. +			sd->found_char[ch] = i; // the char_id of the new char
  6863. +	}
  6864. +	return 1;
  6865. +}
  6866. +
  6867. +int char_parse_delchar(int fd,struct char_session_data* sd, int cmd){
  6868. +	char email[40];
  6869. +	int i, ch;
  6870. +
  6871. +	if (cmd == 0x68) FIFOSD_CHECK(46)
  6872. +	else if (cmd == 0x1fb) FIFOSD_CHECK(56)
  6873. +	else return 0;
  6874. +
  6875. +	{
  6876. +		int cid = RFIFOL(fd,2);
  6877. +
  6878. +		ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
  6879. +		memcpy(email, RFIFOP(fd,6), 40);
  6880. +		RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  6881. +
  6882. +		// Check if e-mail is correct
  6883. +		if(strcmpi(email, sd->email) && //email does not matches and
  6884. +		(
  6885. +			strcmp("[email protected]", sd->email) || //it is not default email, or
  6886. +			(strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
  6887. +		)) {	//Fail
  6888. +			WFIFOHEAD(fd,3);
  6889. +			WFIFOW(fd,0) = 0x70;
  6890. +			WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
  6891. +			WFIFOSET(fd,3);
  6892. +			return 0;
  6893. +		}
  6894. +
  6895. +		// check if this char exists
  6896. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  6897. +		if( i == MAX_CHARS )
  6898. +		{ // Such a character does not exist in the account
  6899. +			WFIFOHEAD(fd,3);
  6900. +			WFIFOW(fd,0) = 0x70;
  6901. +			WFIFOB(fd,2) = 0;
  6902. +			WFIFOSET(fd,3);
  6903. +			return 0;
  6904. +		}
  6905. +
  6906. +		// remove char from list and compact it
  6907. +		for(ch = i; ch < MAX_CHARS-1; ch++)
  6908. +			sd->found_char[ch] = sd->found_char[ch+1];
  6909. +		sd->found_char[MAX_CHARS-1] = -1;
  6910. +
  6911. +		/* Delete character */
  6912. +		if(delete_char_sql(cid)<0){
  6913. +			//can't delete the char
  6914. +			//either SQL error or can't delete by some CONFIG conditions
  6915. +			//del fail
  6916. +			WFIFOHEAD(fd,3);
  6917. +			WFIFOW(fd, 0) = 0x70;
  6918. +			WFIFOB(fd, 2) = 0;
  6919. +			WFIFOSET(fd, 3);
  6920. +			return 0;
  6921. +		}
  6922. +		/* Char successfully deleted.*/
  6923. +		WFIFOHEAD(fd,2);
  6924. +		WFIFOW(fd,0) = 0x6f;
  6925. +		WFIFOSET(fd,2);
  6926. +	}
  6927. +	return 1;
  6928. +}
  6929. +
  6930. +// R 0187 <account ID>.l
  6931. +int char_parse_keepalive(int fd){
  6932. +	if (RFIFOREST(fd) < 6)
  6933. +		return 0;
  6934. +	//int aid = RFIFOL(fd,2);
  6935. +	RFIFOSKIP(fd,6);
  6936. +	return 1;
  6937. +}
  6938. +
  6939. +// R 08fc <char ID>.l <new name>.24B
  6940. +// R 028d <account ID>.l <char ID>.l <new name>.24B
  6941. +int char_parse_reqrename(int fd, struct char_session_data* sd, int cmd){
  6942. +	if(cmd == 0x8fc) FIFOSD_CHECK(30)
  6943. +	if(cmd == 0x28d) FIFOSD_CHECK(34)
  6944. +	else return 0;
  6945. +
  6946. +	{
  6947. +		int i, cid=0;
  6948. +		char name[NAME_LENGTH];
  6949. +		char esc_name[NAME_LENGTH*2+1];
  6950. +		safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
  6951. +
  6952. +		if(cmd == 0x8fc){
  6953. +			cid =RFIFOL(fd,2);
  6954. +			RFIFOSKIP(fd,30);
  6955. +		}
  6956. +		else if(cmd == 0x28d) {
  6957. +			int aid = RFIFOL(fd,2);
  6958. +			cid =RFIFOL(fd,6);
  6959. +			if( aid != sd->account_id )
  6960. +				return 0;
  6961. +			RFIFOSKIP(fd,34);
  6962. +		}
  6963. +
  6964. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  6965. +		if( i == MAX_CHARS )
  6966. +			return 0;
  6967. +
  6968. +		normalize_name(name,TRIM_CHARS);
  6969. +		Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  6970. +		if( !check_char_name(name,esc_name) )
  6971. +		{
  6972. +			i = 1;
  6973. +			safestrncpy(sd->new_name, name, NAME_LENGTH);
  6974. +		}
  6975. +		else
  6976. +			i = 0;
  6977. +
  6978. +		WFIFOHEAD(fd, 4);
  6979. +		WFIFOW(fd,0) = 0x28e;
  6980. +		WFIFOW(fd,2) = i;
  6981. +		WFIFOSET(fd,4);
  6982. +	}
  6983. +	return 1;
  6984. +}
  6985. +
  6986. +// 0x28f <char_id>.L
  6987. +int char_parse_ackrename(int fd, struct char_session_data* sd){
  6988. +	// 0: Sucessfull
  6989. +	// 1: This character's name has already been changed. You cannot change a character's name more than once.
  6990. +	// 2: User information is not correct.
  6991. +	// 3: You have failed to change this character's name.
  6992. +	// 4: Another user is using this character name, so please select another one.
  6993. +	FIFOSD_CHECK(6)
  6994. +
  6995. +	{
  6996. +		int i;
  6997. +		int cid = RFIFOL(fd,2);
  6998. +		RFIFOSKIP(fd,6);
  6999. +
  7000. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  7001. +		if( i == MAX_CHARS )
  7002. +			return 0;
  7003. +		i = rename_char_sql(sd, cid);
  7004. +
  7005. +		WFIFOHEAD(fd, 4);
  7006. +		WFIFOW(fd,0) = 0x290;
  7007. +		WFIFOW(fd,2) = i;
  7008. +		WFIFOSET(fd,4);
  7009. +	}
  7010. +	return 1;
  7011. +}
  7012. +
  7013. +// R 07e5 <?>.w <aid>.l
  7014. +int char_parse_reqcaptcha(int fd){
  7015. +	WFIFOHEAD(fd,5);
  7016. +	WFIFOW(fd,0) = 0x7e9;
  7017. +	WFIFOW(fd,2) = 5;
  7018. +	WFIFOB(fd,4) = 1;
  7019. +	WFIFOSET(fd,5);
  7020. +	RFIFOSKIP(fd,8);
  7021. +	return 1;
  7022. +}
  7023. +
  7024. +// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  7025. +int char_parse_chkcaptcha(int fd){
  7026. +	WFIFOHEAD(fd,5);
  7027. +	WFIFOW(fd,0) = 0x7e9;
  7028. +	WFIFOW(fd,2) = 5;
  7029. +	WFIFOB(fd,4) = 1;
  7030. +	WFIFOSET(fd,5);
  7031. +	RFIFOSKIP(fd,32);
  7032. +	return 1;
  7033. +}
  7034. +
  7035. +
  7036. +int parse_char(int fd)
  7037. +{
  7038. +	unsigned short cmd;
  7039. +	struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
  7040. +	uint32 ipl = session[fd]->client_addr;
  7041. +
  7042. +	// disconnect any player if no login-server.
  7043. +	if(login_fd < 0)
  7044. +		set_eof(fd);
  7045. +
  7046. +	if(session[fd]->flag.eof)
  7047. +	{
  7048. +		if( sd != NULL && sd->auth )
  7049. +		{	// already authed client
  7050. +			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
  7051. +			if( data != NULL && data->fd == fd)
  7052. +				data->fd = -1;
  7053. +			if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
  7054. +				set_char_offline(-1,sd->account_id);
  7055. +		}
  7056. +		do_close(fd);
  7057. +		return 0;
  7058. +	}
  7059. +
  7060. +	while( RFIFOREST(fd) >= 2 )
  7061. +	{
  7062. +		cmd = RFIFOW(fd,0);
  7063. +		switch( cmd )
  7064. +		{
  7065. +
  7066. +		case 0x65: char_parse_reqtoconnect(fd,sd,ipl); break;
  7067. +		// char select
  7068. +		case 0x66: char_parse_charselect(fd,sd,ipl); break;
  7069. +		// createnewchar
  7070. +		case 0x970: char_parse_createnewchar(fd,sd,cmd); break;
  7071. +		case 0x67: char_parse_createnewchar(fd,sd,cmd); break;
  7072. +		// delete char
  7073. +		case 0x68: char_parse_delchar(fd,sd,cmd); break; //
  7074. +		case 0x1fb: char_parse_delchar(fd,sd,cmd); break; // 2004-04-19aSakexe+ langtype 12 char deletion packet
  7075. +		// client keep-alive packet (every 12 seconds)
  7076. +		case 0x187: char_parse_keepalive(fd); break;
  7077. +		// char rename
  7078. +		case 0x8fc: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  7079. +		case 0x28d: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  7080. +		case 0x28f: char_parse_ackrename(fd,sd); break; //Confirm change name.
  7081. +		// captcha
  7082. +		case 0x7e5: char_parse_reqcaptcha(fd); break; // captcha code request (not implemented)
  7083. +		case 0x7e7: char_parse_chkcaptcha(fd); break; // captcha code check (not implemented)
  7084. +		// deletion timer request
  7085. +		case 0x827: char_parse_delete2_req(fd, sd); break;
  7086. +		// deletion accept request
  7087. +		case 0x829: char_parse_delete2_accept(fd, sd); break;
  7088. +		// deletion cancel request
  7089. +		case 0x82b: char_parse_delete2_cancel(fd, sd); break;
  7090. +		// login as map-server
  7091. +		case 0x2af8: char_parse_maplogin(fd); return 0; // avoid processing of followup packets here
  7092. +		//pincode
  7093. +		case 0x8b8: char_parse_pincode_check( fd, sd ); break; // checks the entered pin
  7094. +		case 0x8c5: char_parse_reqpincode_window(fd,sd); break; // request for PIN window
  7095. +		case 0x8be: char_parse_pincode_change( fd, sd ); break; // pincode change request
  7096. +		case 0x8ba: char_parse_pincode_setnew( fd, sd ); break; // activate PIN system and set first PIN
  7097. +		// character movement request
  7098. +		case 0x8d4: char_parse_moveCharSlot(fd,sd); break;
  7099. +		case 0x9a1: char_parse_req_charlist(fd,sd); break;
  7100. +		// unknown packet received
  7101. +		default:
  7102. +			ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL));
  7103. +			set_eof(fd);
  7104. +			return 0;
  7105. +		}
  7106. +	}
  7107. +
  7108. +	RFIFOFLUSH(fd);
  7109. +	return 0;
  7110. +}
  7111. +
  7112. +///
  7113. +/// Login IF
  7114. +///
  7115. +
  7116. +int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
  7117. +{
  7118. +	if (login_fd > 0 && session[login_fd] != NULL)
  7119. +		return 0;
  7120. +
  7121. +	ShowInfo("Attempt to connect to login-server...\n");
  7122. +	login_fd = make_connection(login_ip, login_port, false,10);
  7123. +	if (login_fd == -1)
  7124. +	{	//Try again later. [Skotlex]
  7125. +		login_fd = 0;
  7126. +		return 0;
  7127. +	}
  7128. +	session[login_fd]->func_parse = parse_fromlogin;
  7129. +	session[login_fd]->flag.server = 1;
  7130. +	realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  7131. +
  7132. +	WFIFOHEAD(login_fd,86);
  7133. +	WFIFOW(login_fd,0) = 0x2710;
  7134. +	memcpy(WFIFOP(login_fd,2), userid, 24);
  7135. +	memcpy(WFIFOP(login_fd,26), passwd, 24);
  7136. +	WFIFOL(login_fd,50) = 0;
  7137. +	WFIFOL(login_fd,54) = htonl(char_ip);
  7138. +	WFIFOW(login_fd,58) = htons(char_port);
  7139. +	memcpy(WFIFOP(login_fd,60), server_name, 20);
  7140. +	WFIFOW(login_fd,80) = 0;
  7141. +	WFIFOW(login_fd,82) = char_maintenance;
  7142. +	WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
  7143. +	WFIFOSET(login_fd,86);
  7144. +
  7145. +	return 1;
  7146. +}
  7147. +
  7148. +int char_parselog_ackconnect(int fd, struct char_session_data* sd){
  7149. +	if (RFIFOREST(fd) < 3)
  7150. +		return 0;
  7151. +
  7152. +	if (RFIFOB(fd,2)) {
  7153. +		//printf("connect login server error : %d\n", RFIFOB(fd,2));
  7154. +		ShowError("Can not connect to login-server.\n");
  7155. +		ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  7156. +		ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
  7157. +		ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
  7158. +		set_eof(fd);
  7159. +		return 0;
  7160. +	} else {
  7161. +		ShowStatus("Connected to login-server (connection #%d).\n", fd);
  7162. +		loginif_on_ready();
  7163. +	}
  7164. +	RFIFOSKIP(fd,3);
  7165. +	return 1;
  7166. +}
  7167. +
  7168. +int char_parselog_ackaccreq(int fd, struct char_session_data* sd){
  7169. +	if (RFIFOREST(fd) < 25)
  7170. +		return 0;
  7171. +	{
  7172. +		int account_id = RFIFOL(fd,2);
  7173. +		uint32 login_id1 = RFIFOL(fd,6);
  7174. +		uint32 login_id2 = RFIFOL(fd,10);
  7175. +		uint8 sex = RFIFOB(fd,14);
  7176. +		uint8 result = RFIFOB(fd,15);
  7177. +		int request_id = RFIFOL(fd,16);
  7178. +		uint32 version = RFIFOL(fd,20);
  7179. +		uint8 clienttype = RFIFOB(fd,24);
  7180. +		RFIFOSKIP(fd,25);
  7181. +
  7182. +		if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
  7183. +			!sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
  7184. +		{
  7185. +			int client_fd = request_id;
  7186. +			sd->version = version;
  7187. +			sd->clienttype = clienttype;
  7188. +			switch( result )
  7189. +			{
  7190. +			case 0:// ok
  7191. +				char_auth_ok(client_fd, sd);
  7192. +				break;
  7193. +			case 1:// auth failed
  7194. +				WFIFOHEAD(client_fd,3);
  7195. +				WFIFOW(client_fd,0) = 0x6c;
  7196. +				WFIFOB(client_fd,2) = 0;// rejected from server
  7197. +				WFIFOSET(client_fd,3);
  7198. +				break;
  7199. +			}
  7200. +		}
  7201. +	}
  7202. +	return 1;
  7203. +}
  7204. +
  7205. +void char_pincode_start(int fd, struct char_session_data* sd){
  7206. +	if( pincode_enabled ){
  7207. +		// PIN code system enabled
  7208. +		if( strlen( sd->pincode ) <= 0 ){
  7209. +			// No PIN code has been set yet
  7210. +			if( pincode_force ){
  7211. +				pincode_sendstate( fd, sd, PINCODE_NEW );
  7212. +			}else{
  7213. +				pincode_sendstate( fd, sd, PINCODE_PASSED );
  7214. +			}
  7215. +		}else{
  7216. +			if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
  7217. +				struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
  7218. +
  7219. +				if( node != NULL && node->pincode_success ){
  7220. +					// User has already passed the check
  7221. +					pincode_sendstate( fd, sd, PINCODE_PASSED );
  7222. +				}else{
  7223. +					// Ask user for his PIN code
  7224. +					pincode_sendstate( fd, sd, PINCODE_ASK );
  7225. +				}
  7226. +			}else{
  7227. +				// User hasnt changed his PIN code too long
  7228. +				pincode_sendstate( fd, sd, PINCODE_EXPIRED );
  7229. +			}
  7230. +		}
  7231. +	}else{
  7232. +		// PIN code system disabled
  7233. +		pincode_sendstate( fd, sd, PINCODE_OK );
  7234. +	}
  7235. +}
  7236. +
  7237. +int char_parselog_reqaccdata(int fd, struct char_session_data* sd){
  7238. +	int u_fd; //user fd
  7239. +	if (RFIFOREST(fd) < 72)
  7240. +		return 0;
  7241. +
  7242. +	// find the authenticated session with this account id
  7243. +	ARR_FIND( 0, fd_max, u_fd, session[u_fd] && (sd = (struct char_session_data*)session[u_fd]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) );
  7244. +	if( u_fd < fd_max )
  7245. +	{
  7246. +		int server_id;
  7247. +		memcpy(sd->email, RFIFOP(fd,6), 40);
  7248. +		sd->expiration_time = (time_t)RFIFOL(fd,46);
  7249. +		sd->group_id = RFIFOB(fd,50);
  7250. +		sd->char_slots = RFIFOB(fd,51);
  7251. +		if( sd->char_slots > MAX_CHARS ) {
  7252. +			ShowError("Account '%d' `character_slots` column is higher than supported MAX_CHARS (%d), update MAX_CHARS in mmo.h! capping to MAX_CHARS...\n",sd->account_id,sd->char_slots);
  7253. +			sd->char_slots = MAX_CHARS;/* cap to maximum */
  7254. +		} else if ( !sd->char_slots )/* no value aka 0 in sql */
  7255. +			sd->char_slots = MAX_CHARS;/* cap to maximum */
  7256. +		safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
  7257. +		safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
  7258. +		sd->pincode_change = (time_t)RFIFOL(fd,68);
  7259. +		ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
  7260. +		// continued from char_auth_ok...
  7261. +		if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
  7262. +			(max_connect_user == 0 && sd->group_id != gm_allow_group) ||
  7263. +			( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
  7264. +			// refuse connection (over populated)
  7265. +			WFIFOHEAD(u_fd,3);
  7266. +			WFIFOW(u_fd,0) = 0x6c;
  7267. +			WFIFOW(u_fd,2) = 0;
  7268. +			WFIFOSET(u_fd,3);
  7269. +		} else {
  7270. +			// send characters to player
  7271. +			mmo_char_send(u_fd, sd);
  7272. +			if(sd->version >= date2version(20110309)){
  7273. +				ShowInfo("Asking to start pincode\n");
  7274. +				char_pincode_start(u_fd,sd);
  7275. +			}
  7276. +		}
  7277. +	}
  7278. +	RFIFOSKIP(fd,72);
  7279. +	return 1;
  7280. +}
  7281. +
  7282. +int char_parselog_keepalive(int fd, struct char_session_data* sd){
  7283. +	if (RFIFOREST(fd) < 2)
  7284. +		return 0;
  7285. +	RFIFOSKIP(fd,2);
  7286. +	session[fd]->flag.ping = 0;
  7287. +	return 1;
  7288. +}
  7289. +
  7290. +int char_parselog_ackchangesex(int fd, struct char_session_data* sd){
  7291. +	if (RFIFOREST(fd) < 7)
  7292. +		return 0;
  7293. +	{
  7294. +		unsigned char buf[7];
  7295. +		int i;
  7296. +
  7297. +		int acc = RFIFOL(fd,2);
  7298. +		int sex = RFIFOB(fd,6);
  7299. +		RFIFOSKIP(fd,7);
  7300. +
  7301. +		if( acc > 0 )
  7302. +		{// TODO: Is this even possible?
  7303. +			int char_id[MAX_CHARS];
  7304. +			int class_[MAX_CHARS];
  7305. +			int guild_id[MAX_CHARS];
  7306. +			int num;
  7307. +			char* data;
  7308. +
  7309. +			struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
  7310. +			if( node != NULL )
  7311. +				node->sex = sex;
  7312. +
  7313. +			// get characters
  7314. +			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
  7315. +				Sql_ShowDebug(sql_handle);
  7316. +			for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
  7317. +			{
  7318. +				Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
  7319. +				Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
  7320. +				Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
  7321. +			}
  7322. +			num = i;
  7323. +			for( i = 0; i < num; ++i )
  7324. +			{
  7325. +				if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
  7326. +					class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
  7327. +					class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
  7328. +					class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
  7329. +					class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
  7330. +					class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
  7331. +					class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  7332. +				{
  7333. +					// job modification
  7334. +					if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
  7335. +						class_[i] = (sex ? JOB_BARD : JOB_DANCER);
  7336. +					else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
  7337. +						class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
  7338. +					else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
  7339. +						class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
  7340. +					else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
  7341. +						class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
  7342. +					else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
  7343. +						class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
  7344. +					else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
  7345. +						class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
  7346. +					else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  7347. +						class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
  7348. +				}
  7349. +
  7350. +				if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) )
  7351. +					Sql_ShowDebug(sql_handle);
  7352. +
  7353. +				if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
  7354. +					inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
  7355. +			}
  7356. +			Sql_FreeResult(sql_handle);
  7357. +
  7358. +			// disconnect player if online on char-server
  7359. +			disconnect_player(acc);
  7360. +		}
  7361. +
  7362. +		// notify all mapservers about this change
  7363. +		WBUFW(buf,0) = 0x2b0d;
  7364. +		WBUFL(buf,2) = acc;
  7365. +		WBUFB(buf,6) = sex;
  7366. +		mapif_sendall(buf, 7);
  7367. +	}
  7368. +	return 1;
  7369. +}
  7370. +
  7371. +int char_parselog_ackacc2req(int fd, struct char_session_data* sd){
  7372. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  7373. +		return 0;
  7374. +
  7375. +	{	//Receive account_reg2 registry, forward to map servers.
  7376. +		unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
  7377. +		memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  7378. +		WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  7379. +		mapif_sendall(buf, WBUFW(buf,2));
  7380. +		RFIFOSKIP(fd, RFIFOW(fd,2));
  7381. +	}
  7382. +	return 1;
  7383. +}
  7384. +
  7385. +int char_parselog_accbannotification(int fd, struct char_session_data* sd){
  7386. +	if (RFIFOREST(fd) < 11)
  7387. +		return 0;
  7388. +
  7389. +	{	// send to all map-servers to disconnect the player
  7390. +		unsigned char buf[11];
  7391. +		WBUFW(buf,0) = 0x2b14;
  7392. +		WBUFL(buf,2) = RFIFOL(fd,2);
  7393. +		WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  7394. +		WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  7395. +		mapif_sendall(buf, 11);
  7396. +	}
  7397. +	// disconnect player if online on char-server
  7398. +	disconnect_player(RFIFOL(fd,2));
  7399. +	RFIFOSKIP(fd,11);
  7400. +	return 1;
  7401. +}
  7402. +
  7403. +int char_parselog_askkick(int fd, struct char_session_data* sd){
  7404. +	if (RFIFOREST(fd) < 6)
  7405. +		return 0;
  7406. +	{
  7407. +		int aid = RFIFOL(fd,2);
  7408. +		struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
  7409. +		RFIFOSKIP(fd,6);
  7410. +		if( character != NULL )
  7411. +		{// account is already marked as online!
  7412. +			if( character->server > -1 )
  7413. +			{	//Kick it from the map server it is on.
  7414. +				mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  7415. +				if (character->waiting_disconnect == INVALID_TIMER)
  7416. +					character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
  7417. +			}
  7418. +			else
  7419. +			{// Manual kick from char server.
  7420. +				struct char_session_data *tsd;
  7421. +				int i;
  7422. +				ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
  7423. +				if( i < fd_max )
  7424. +				{
  7425. +					char_send_auth_result(i,2);  //Send "Someone has already logged in with this id"
  7426. +					set_eof(i);
  7427. +				}
  7428. +				else // still moving to the map-server
  7429. +					set_char_offline(-1, aid);
  7430. +			}
  7431. +		}
  7432. +		idb_remove(auth_db, aid);// reject auth attempts from map-server
  7433. +	}
  7434. +	return 1;
  7435. +}
  7436. +
  7437. +int char_parselog_updip(int fd, struct char_session_data* sd){
  7438. +	if (RFIFOREST(fd) < 2)
  7439. +		return 0;
  7440. +	{
  7441. +		unsigned char buf[2];
  7442. +		uint32 new_ip = 0;
  7443. +
  7444. +		WBUFW(buf,0) = 0x2b1e;
  7445. +		mapif_sendall(buf, 2);
  7446. +
  7447. +		new_ip = host2ip(login_ip_str);
  7448. +		if (new_ip && new_ip != login_ip)
  7449. +			login_ip = new_ip; //Update login ip, too.
  7450. +
  7451. +		new_ip = host2ip(char_ip_str);
  7452. +		if (new_ip && new_ip != char_ip)
  7453. +		{	//Update ip.
  7454. +			char_ip = new_ip;
  7455. +			ShowInfo("Updating IP for [%s].\n", char_ip_str);
  7456. +			// notify login server about the change
  7457. +			WFIFOHEAD(fd,6);
  7458. +			WFIFOW(fd,0) = 0x2736;
  7459. +			WFIFOL(fd,2) = htonl(char_ip);
  7460. +			WFIFOSET(fd,6);
  7461. +		}
  7462. +
  7463. +		RFIFOSKIP(fd,2);
  7464. +	}
  7465. +	return 1;
  7466. +}
  7467. +
  7468. +int parse_fromlogin(int fd) {
  7469. +	struct char_session_data* sd = NULL;
  7470. +
  7471. +	// only process data from the login-server
  7472. +	if( fd != login_fd ) {
  7473. +		ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
  7474. +		do_close(fd);
  7475. +		return 0;
  7476. +	}
  7477. +
  7478. +	if( session[fd]->flag.eof ) {
  7479. +		do_close(fd);
  7480. +		login_fd = -1;
  7481. +		loginif_on_disconnect();
  7482. +		return 0;
  7483. +	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
  7484. +		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
  7485. +			set_eof(fd);
  7486. +			return 0;
  7487. +		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
  7488. +			WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
  7489. +			WFIFOW(fd,0) = 0x2719;
  7490. +			WFIFOSET(fd,2);
  7491. +
  7492. +			session[fd]->flag.ping = 2;
  7493. +		}
  7494. +	}
  7495. +
  7496. +	sd = (struct char_session_data*)session[fd]->session_data;
  7497. +
  7498. +	while(RFIFOREST(fd) >= 2) {
  7499. +		uint16 command = RFIFOW(fd,0);
  7500. +
  7501. +		switch( command )
  7502. +		{
  7503. +		// acknowledgement of connect-to-loginserver request
  7504. +		case 0x2711: char_parselog_ackconnect(fd,sd); break;
  7505. +		// acknowledgement of account authentication request
  7506. +		case 0x2713: char_parselog_ackaccreq(fd, sd); break;
  7507. +		// account data
  7508. +		case 0x2717: char_parselog_reqaccdata(fd, sd); break;
  7509. +		// login-server alive packet
  7510. +		case 0x2718: char_parselog_keepalive(fd, sd); break;
  7511. +		// changesex reply
  7512. +		case 0x2723: char_parselog_ackchangesex(fd, sd); break;
  7513. +		// reply to an account_reg2 registry request
  7514. +		case 0x2729: char_parselog_ackacc2req(fd, sd); break;
  7515. +		// State change of account/ban notification (from login-server)
  7516. +		case 0x2731: char_parselog_accbannotification(fd, sd); break;
  7517. +		// Login server request to kick a character out. [Skotlex]
  7518. +		case 0x2734: char_parselog_askkick(fd,sd); break;
  7519. +		// ip address update signal from login server
  7520. +		case 0x2735: char_parselog_updip(fd,sd); break;
  7521. +		default:
  7522. +			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
  7523. +			set_eof(fd);
  7524. +			return 0;
  7525. +		}
  7526. +	}
  7527. +
  7528. +	RFIFOFLUSH(fd);
  7529. +	return 0;
  7530. +}
  7531. +
  7532. +
  7533. +
  7534. +
  7535. +/*======================================================
  7536. + * Login-Server help option info
  7537. + *------------------------------------------------------*/
  7538. +void display_helpscreen(bool do_exit)
  7539. +{
  7540. +	ShowInfo("Usage: %s [options]\n", SERVER_NAME);
  7541. +	ShowInfo("\n");
  7542. +	ShowInfo("Options:\n");
  7543. +	ShowInfo("  -?, -h [--help]\t\tDisplays this help screen.\n");
  7544. +	ShowInfo("  -v [--version]\t\tDisplays the server's version.\n");
  7545. +	ShowInfo("  --run-once\t\t\tCloses server after loading (testing).\n");
  7546. +	ShowInfo("  --char-config <file>\t\tAlternative char-server configuration.\n");
  7547. +	ShowInfo("  --lan-config <file>\t\tAlternative lag configuration.\n");
  7548. +	ShowInfo("  --inter-config <file>\t\tAlternative inter-server configuration.\n");
  7549. +	ShowInfo("  --msg-config <file>\t\tAlternative message configuration.\n");
  7550. +	if( do_exit )
  7551. +		exit(EXIT_SUCCESS);
  7552. +}
  7553. +
  7554. +int char_msg_config_read(char *cfgName){
  7555. +	return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
  7556. +}
  7557. +const char* char_msg_txt(int msg_number){
  7558. +	return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
  7559. +}
  7560. +void char_do_final_msg(void){
  7561. +	_do_final_msg(CHAR_MAX_MSG,msg_table);
  7562. +}
  7563. +
  7564. +
  7565. +
  7566.  void do_final(void)
  7567.  {
  7568.  	ShowStatus("Terminating...\n");
  7569. @@ -5188,6 +5314,12 @@
  7570.  	ShowStatus("Finished.\n");
  7571.  }
  7572.  
  7573. +
  7574. +void set_server_type(void)
  7575. +{
  7576. +	SERVER_TYPE = ATHENA_SERVER_CHAR;
  7577. +}
  7578. +
  7579.  //------------------------------
  7580.  // Function called when the server
  7581.  // has received a crash signal.
  7582. @@ -5196,12 +5328,6 @@
  7583.  {
  7584.  }
  7585.  
  7586. -void set_server_type(void)
  7587. -{
  7588. -	SERVER_TYPE = ATHENA_SERVER_CHAR;
  7589. -}
  7590. -
  7591. -
  7592.  /// Called when a terminate signal is received.
  7593.  void do_shutdown(void)
  7594.  {
  7595. @@ -5317,33 +5443,4 @@
  7596.  		add_timer_interval(gettick()+1000, parse_console_timer, 0, 0, 1000); //start in 1s each 1sec
  7597.  	}
  7598.  	return 0;
  7599. -}
  7600. -
  7601. -int char_msg_config_read(char *cfgName){
  7602. -	return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
  7603. -}
  7604. -const char* char_msg_txt(int msg_number){
  7605. -	return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
  7606. -}
  7607. -void char_do_final_msg(void){
  7608. -	_do_final_msg(CHAR_MAX_MSG,msg_table);
  7609. -}
  7610. -
  7611. -/*======================================================
  7612. - * Login-Server help option info
  7613. - *------------------------------------------------------*/
  7614. -void display_helpscreen(bool do_exit)
  7615. -{
  7616. -	ShowInfo("Usage: %s [options]\n", SERVER_NAME);
  7617. -	ShowInfo("\n");
  7618. -	ShowInfo("Options:\n");
  7619. -	ShowInfo("  -?, -h [--help]\t\tDisplays this help screen.\n");
  7620. -	ShowInfo("  -v [--version]\t\tDisplays the server's version.\n");
  7621. -	ShowInfo("  --run-once\t\t\tCloses server after loading (testing).\n");
  7622. -	ShowInfo("  --char-config <file>\t\tAlternative char-server configuration.\n");
  7623. -	ShowInfo("  --lan-config <file>\t\tAlternative lag configuration.\n");
  7624. -	ShowInfo("  --inter-config <file>\t\tAlternative inter-server configuration.\n");
  7625. -	ShowInfo("  --msg-config <file>\t\tAlternative message configuration.\n");
  7626. -	if( do_exit )
  7627. -		exit(EXIT_SUCCESS);
  7628. -}
  7629. +}
  7630. \ No newline at end of file
  7631. Index: src/common/timer.c
  7632. ===================================================================
  7633. --- src/common/timer.c	(revision 17365)
  7634. +++ src/common/timer.c	(working copy)
  7635. @@ -109,28 +109,28 @@
  7636.  	} t;
  7637.  
  7638.  	asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1]) );
  7639. -	
  7640. +
  7641.  	return t.qw;
  7642.  }
  7643.  
  7644.  static void rdtsc_calibrate(){
  7645.  	uint64 t1, t2;
  7646.  	int32 i;
  7647. -	
  7648. +
  7649.  	ShowStatus("Calibrating Timer Source, please wait... ");
  7650. -	
  7651. +
  7652.  	RDTSC_CLOCK = 0;
  7653. -	
  7654. +
  7655.  	for(i = 0; i < 5; i++){
  7656.  		t1 = _rdtsc();
  7657.  		usleep(1000000); //1000 MS
  7658.  		t2 = _rdtsc();
  7659. -		RDTSC_CLOCK += (t2 - t1) / 1000; 
  7660. +		RDTSC_CLOCK += (t2 - t1) / 1000;
  7661.  	}
  7662.  	RDTSC_CLOCK /= 5;
  7663. -	
  7664. +
  7665.  	RDTSC_BEGINTICK = _rdtsc();
  7666. -	
  7667. +
  7668.  	ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000) );
  7669.  }
  7670.  
  7671. @@ -243,7 +243,7 @@
  7672.  int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data)
  7673.  {
  7674.  	int tid;
  7675. -	
  7676. +
  7677.  	tid = acquire_timer();
  7678.  	timer_data[tid].tick     = tick;
  7679.  	timer_data[tid].func     = func;
  7680. @@ -267,7 +267,7 @@
  7681.  		ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick()));
  7682.  		return INVALID_TIMER;
  7683.  	}
  7684. -	
  7685. +
  7686.  	tid = acquire_timer();
  7687.  	timer_data[tid].tick     = tick;
  7688.  	timer_data[tid].func     = func;
  7689. @@ -320,7 +320,7 @@
  7690.  int settick_timer(int tid, unsigned int tick)
  7691.  {
  7692.  	size_t i;
  7693. -	
  7694. +
  7695.  	// search timer position
  7696.  	ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid);
  7697.  	if( i == BHEAP_LENGTH(timer_heap) )
  7698. @@ -406,6 +406,16 @@
  7699.  	return (unsigned long)difftime(time(NULL), start_time);
  7700.  }
  7701.  
  7702. +//-----------------------------------------------------
  7703. +// custom timestamp formatting (from eApp)
  7704. +//-----------------------------------------------------
  7705. +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
  7706. +{
  7707. +	size_t len = strftime(str, size, format, localtime(&timestamp));
  7708. +	memset(str + len, '\0', size - len);
  7709. +	return str;
  7710. +}
  7711. +
  7712.  void timer_init(void)
  7713.  {
  7714.  #if defined(ENABLE_RDTSC)
  7715. Index: src/common/timer.h
  7716. ===================================================================
  7717. --- src/common/timer.h	(revision 17365)
  7718. +++ src/common/timer.h	(working copy)
  7719. @@ -5,6 +5,7 @@
  7720.  #define	_TIMER_H_
  7721.  
  7722.  #include "../common/cbasetypes.h"
  7723. +#include <time.h>
  7724.  
  7725.  #define DIFF_TICK(a,b) ((int)((a)-(b)))
  7726.  
  7727. @@ -51,6 +52,9 @@
  7728.  
  7729.  unsigned long get_uptime(void);
  7730.  
  7731. +//transform a timestamp to string
  7732. +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format);
  7733. +
  7734.  int do_timer(unsigned int tick);
  7735.  void timer_init(void);
  7736.  void timer_final(void);
  7737. Index: src/common/mmo.h
  7738. ===================================================================
  7739. --- src/common/mmo.h	(revision 17365)
  7740. +++ src/common/mmo.h	(working copy)
  7741. @@ -8,47 +8,9 @@
  7742.  #include "../common/db.h"
  7743.  #include <time.h>
  7744.  
  7745. -// server->client protocol version
  7746. -//        0 - pre-?
  7747. -//        1 - ?                    - 0x196
  7748. -//        2 - ?                    - 0x78, 0x79
  7749. -//        3 - ?                    - 0x1c8, 0x1c9, 0x1de
  7750. -//        4 - ?                    - 0x1d7, 0x1d8, 0x1d9, 0x1da
  7751. -//        5 - 2003-12-18aSakexe+   - 0x1ee, 0x1ef, 0x1f0, ?0x1c4, 0x1c5?
  7752. -//        6 - 2004-03-02aSakexe+   - 0x1f4, 0x1f5
  7753. -//        7 - 2005-04-11aSakexe+   - 0x229, 0x22a, 0x22b, 0x22c
  7754. -// 20061023 - 2006-10-23aSakexe+   - 0x6b, 0x6d
  7755. -// 20070521 - 2007-05-21aSakexe+   - 0x283
  7756. -// 20070821 - 2007-08-21aSakexe+   - 0x2c5
  7757. -// 20070918 - 2007-09-18aSakexe+   - 0x2d7, 0x2d9, 0x2da
  7758. -// 20071106 - 2007-11-06aSakexe+   - 0x78, 0x7c, 0x22c
  7759. -// 20080102 - 2008-01-02aSakexe+   - 0x2ec, 0x2ed , 0x2ee
  7760. -// 20081126 - 2008-11-26aSakexe+   - 0x1a2
  7761. -// 20090408 - 2009-04-08aSakexe+   - 0x44a (dont use as it overlaps with RE client packets)
  7762. -// 20080827 - 2008-08-27aRagexeRE+ - First RE Client
  7763. -// 20081217 - 2008-12-17aRagexeRE+ - 0x6d (Note: This one still use old Char Info Packet Structure)
  7764. -// 20081218 - 2008-12-17bRagexeRE+ - 0x6d (Note: From this one client use new Char Info Packet Structure)
  7765. -// 20090603 - 2009-06-03aRagexeRE+ - 0x7d7, 0x7d8, 0x7d9, 0x7da
  7766. -// 20090617 - 2009-06-17aRagexeRE+ - 0x7d9
  7767. -// 20090922 - 2009-09-22aRagexeRE+ - 0x7e5, 0x7e7, 0x7e8, 0x7e9
  7768. -// 20091103 - 2009-11-03aRagexeRE+ - 0x7f7, 0x7f8, 0x7f9
  7769. -// 20100105 - 2010-01-05aRagexeRE+ - 0x133, 0x800, 0x801
  7770. -// 20100126 - 2010-01-26aRagexeRE+ - 0x80e
  7771. -// 20100223 - 2010-02-23aRagexeRE+ - 0x80f
  7772. -// 20100413 - 2010-04-13aRagexeRE+ - 0x6b
  7773. -// 20100629 - 2010-06-29aRagexeRE+ - 0x2d0, 0xaa, 0x2d1, 0x2d2
  7774. -// 20100721 - 2010-07-21aRagexeRE+ - 0x6b, 0x6d
  7775. -// 20100727 - 2010-07-27aRagexeRE+ - 0x6b, 0x6d
  7776. -// 20100803 - 2010-08-03aRagexeRE+ - 0x6b, 0x6d, 0x827, 0x828, 0x829, 0x82a, 0x82b, 0x82c, 0x842, 0x843
  7777. -// 20101124 - 2010-11-24aRagexeRE+ - 0x856, 0x857, 0x858
  7778. -// 20110111 - 2011-01-11aRagexeRE+ - 0x6b, 0x6d
  7779. -// 20110928 - 2011-09-28aRagexeRE+ - 0x6b, 0x6d
  7780. -// 20111025 - 2011-10-25aRagexeRE+ - 0x6b, 0x6d
  7781. -// 20120307 - 2012-03-07aRagexeRE+ - 0x970
  7782. -
  7783.  #ifndef PACKETVER
  7784. -	#define PACKETVER 20120410
  7785. -	//#define PACKETVER 20130320
  7786. +	//#define PACKETVER 20120410
  7787. +	#define PACKETVER 20130320
  7788.  	//#define PACKETVER 20111116
  7789.  #endif
  7790.  
  7791. Index: src/common/utils.c
  7792. ===================================================================
  7793. --- src/common/utils.c	(revision 17365)
  7794. +++ src/common/utils.c	(working copy)
  7795. @@ -109,16 +109,16 @@
  7796.  	WIN32_FIND_DATAA FindFileData;
  7797.  	HANDLE hFind;
  7798.  	char tmppath[MAX_PATH+1];
  7799. -	
  7800. +
  7801.  	const char *path    = (p  ==NULL)? "." : p;
  7802.  	const char *pattern = (pat==NULL)? "" : pat;
  7803. -	
  7804. +
  7805.  	checkpath(tmppath,path);
  7806.  	if( PATHSEP != tmppath[strlen(tmppath)-1])
  7807.  		strcat(tmppath, "\\*");
  7808.  	else
  7809.  		strcat(tmppath, "*");
  7810. -	
  7811. +
  7812.  	hFind = FindFirstFileA(tmppath, &FindFileData);
  7813.  	if (hFind != INVALID_HANDLE_VALUE)
  7814.  	{
  7815. @@ -259,6 +259,46 @@
  7816.  		( (uint32)(word1 << 0x10) );
  7817.  }
  7818.  
  7819. +int date2version(int date){
  7820. +	if(date < 20040906) return 5;
  7821. +	else if(date < 20040920) return 10;
  7822. +	else if(date < 20041005) return 11;
  7823. +	else if(date < 20041025) return 12;
  7824. +	else if(date < 20041129) return 13;
  7825. +	else if(date < 20050110) return 14;
  7826. +	else if(date < 20050509) return 15;
  7827. +	else if(date < 20050628) return 16;
  7828. +	else if(date < 20050718) return 17;
  7829. +	else if(date < 20050719) return 18;
  7830. +	else if(date < 20060327) return 19;
  7831. +	else if(date < 20070108) return 20;
  7832. +	else if(date < 20070212) return 21;
  7833. +	//wtf @FIXME
  7834. +	else if(date < 20080910) return 22;
  7835. +	else if(date < 20080827) return 23;
  7836. +	else if(date < 20080910) return 24;
  7837. +	//unable to solve from date
  7838. +	else if(date < 20101124) return 25;
  7839. +	else if(date < 20111005) return 26;
  7840. +	else if(date < 20111102) return 27;
  7841. +	else if(date < 20120307) return 28;
  7842. +	else if(date < 20120410) return 29;
  7843. +	else if(date < 20120418) return 30;
  7844. +	else if(date < 20120618) return 31;
  7845. +	else if(date < 20120702) return 32;
  7846. +	else if(date < 20130320) return 33;
  7847. +	else if(date < 20130515) return 34;
  7848. +	else if(date < 20130522) return 35;
  7849. +	else if(date < 20130529) return 36;
  7850. +	else if(date < 20130605) return 37;
  7851. +	else if(date < 20130612) return 38;
  7852. +	else if(date >= 20130612) return 39;
  7853. +//	else if(date < 20040920) return 40;
  7854. +//	else if(date < 20040920) return 41;
  7855. +//	else if(date < 20040920) return 42;
  7856. +//	else if(date < 20040920) return 43;
  7857. +	else return 30; //default
  7858. +}
  7859.  
  7860.  /// calculates the value of A / B, in percent (rounded down)
  7861.  unsigned int get_percentage(const unsigned int A, const unsigned int B)
  7862. Index: src/common/utils.h
  7863. ===================================================================
  7864. --- src/common/utils.h	(revision 17365)
  7865. +++ src/common/utils.h	(working copy)
  7866. @@ -29,4 +29,6 @@
  7867.  extern uint16 MakeWord(uint8 byte0, uint8 byte1);
  7868.  extern uint32 MakeDWord(uint16 word0, uint16 word1);
  7869.  
  7870. +int date2version(int date);
  7871. +
  7872.  #endif /* _UTILS_H_ */
  7873. Index: src/common/cli.c
  7874. ===================================================================
  7875. --- src/common/cli.c	(revision 17365)
  7876. +++ src/common/cli.c	(working copy)
  7877. @@ -53,12 +53,12 @@
  7878.   */
  7879.  void display_versionscreen(bool do_exit)
  7880.  {
  7881. -    ShowInfo(CL_WHITE"rAthena SVN version: %s" CL_RESET"\n", get_svn_revision());
  7882. -    ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://rathena.org/\n");
  7883. -    ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.rizon.net/#rathena\n");
  7884. -    ShowInfo("Open "CL_WHITE"readme.txt"CL_RESET" for more information.\n");
  7885. -    if (do_exit)
  7886. -	exit(EXIT_SUCCESS);
  7887. +	ShowInfo(CL_WHITE"rAthena SVN version: %s" CL_RESET"\n", get_svn_revision());
  7888. +	ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://rathena.org/\n");
  7889. +	ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.rizon.net/#rathena\n");
  7890. +	ShowInfo("Open "CL_WHITE"readme.txt"CL_RESET" for more information.\n");
  7891. +	if (do_exit)
  7892. +		exit(EXIT_SUCCESS);
  7893.  }
  7894.  
  7895.  /*
  7896. Index: src/common/cli.h
  7897. ===================================================================
  7898. --- src/common/cli.h	(revision 17365)
  7899. +++ src/common/cli.h	(working copy)
  7900. @@ -32,6 +32,8 @@
  7901.   extern char* MSG_CONF_NAME_EN; //all
  7902.  
  7903.  extern void display_helpscreen(bool exit);
  7904. +void display_versionscreen(bool do_exit);
  7905. +bool opt_has_next_value(const char* option, int i, int argc);
  7906.  int cli_get_options(int argc, char ** argv);
  7907.  int parse_console_timer(int tid, unsigned int tick, int id, intptr_t data);
  7908.  extern int parse_console(const char* buf); //particular for each serv
  7909. Index: src/common/socket.c
  7910. ===================================================================
  7911. --- src/common/socket.c	(revision 17365)
  7912. +++ src/common/socket.c	(working copy)
  7913. @@ -18,7 +18,7 @@
  7914.  	#include "../common/winapi.h"
  7915.  #else
  7916.  	#include <errno.h>
  7917. -	#include <sys/socket.h>
  7918. +	#include <sys/select.h>
  7919.  	#include <netinet/in.h>
  7920.  	#include <netinet/tcp.h>
  7921.  	#include <net/if.h>
  7922. @@ -637,7 +637,7 @@
  7923.  /// advance the RFIFO cursor (marking 'len' bytes as processed)
  7924.  int RFIFOSKIP(int fd, size_t len)
  7925.  {
  7926. -    struct socket_data *s;
  7927. +	struct socket_data *s;
  7928.  
  7929.  	if ( !session_isActive(fd) )
  7930.  		return 0;
  7931.  
Viewed 1964 times, submitted by lighta.