viewing paste Unknown #6305 | 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,7 +82,7 @@
  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.  // Store passwords as MD5 hashes instead of plaintext ?
  13.  // NOTE: Will not work with clients that use <passwordencrypt>
  14. @@ -149,13 +149,14 @@
  15.  // If turned on, the login server will check if the client's hash matches
  16.  // the value below, and will not connect tampered clients.
  17.  // Note: see doc\md5_hashcheck.txt for more details.
  18. -client_hash_check: off
  19. +client_hash_check: yes
  20.  
  21.  // Client MD5 hashes
  22.  // A player can login with a client hash at or below the account group_id.
  23.  // Format: group_id, hash
  24.  client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5
  25. -client_hash: 99, cb1ea78023d337c38e8ba5124e2338ae
  26. +client_hash: 98, cb1ea78023d337c38e8ba5124e2338ae
  27. +client_hash: 99, any
  28.  
  29.  import: conf/inter_athena.conf
  30.  import: conf/import/login_conf.txt
  31. Index: src/login/login.c
  32. ===================================================================
  33. --- src/login/login.c	(revision 17365)
  34. +++ src/login/login.c	(working copy)
  35. @@ -13,6 +13,7 @@
  36.  #include "../common/msg_conf.h"
  37.  #include "../common/cli.h"
  38.  #include "../common/ers.h"
  39. +#include "../common/utils.h"
  40.  #include "account.h"
  41.  #include "ipban.h"
  42.  #include "login.h"
  43. @@ -77,7 +78,6 @@
  44.  #define AUTH_TIMEOUT 30000
  45.  
  46.  struct auth_node {
  47. -
  48.  	int account_id;
  49.  	uint32 login_id1;
  50.  	uint32 login_id2;
  51. @@ -86,7 +86,6 @@
  52.  	uint32 version;
  53.  	uint8 clienttype;
  54.  };
  55. -
  56.  static DBMap* auth_db; // int account_id -> struct auth_node*
  57.  
  58.  
  59. @@ -94,13 +93,12 @@
  60.  // Online User Database [Wizputer]
  61.  //-----------------------------------------------------
  62.  struct online_login_data {
  63. -
  64.  	int account_id;
  65.  	int waiting_disconnect;
  66.  	int char_server;
  67.  };
  68. +static DBMap* online_db; // int account_id -> struct online_login_data*
  69.  
  70. -static DBMap* online_db; // int account_id -> struct online_login_data*
  71.  static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data);
  72.  
  73.  /**
  74. @@ -191,7 +189,85 @@
  75.  	return 0;
  76.  }
  77.  
  78. +//--------------------------------------------
  79. +// Test to know if an IP come from LAN or WAN.
  80. +//--------------------------------------------
  81. +int lan_subnetcheck(uint32 ip)
  82. +{
  83. +	int i;
  84. +	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  85. +	return ( i < subnet_count ) ? subnet[i].char_ip : 0;
  86. +}
  87.  
  88. +//-----------------------
  89. +// Console Command Parser [Wizputer]
  90. +//-----------------------
  91. +int parse_console(const char* buf){
  92. +	char type[64];
  93. +	char command[64];
  94. +	int n=0;
  95. +
  96. +	if( ( n = sscanf(buf, "%127[^:]:%255[^\n\r]", type, command) ) < 2 ){
  97. +		if((n = sscanf(buf, "%63[^\n]", type))<1) return -1; //nothing to do no arg
  98. +	}
  99. +	if( n != 2 ){ //end string
  100. +		ShowNotice("Type: '%s'\n",type);
  101. +		command[0] = '\0';
  102. +	}
  103. +	else
  104. +		ShowNotice("Type of command: '%s' || Command: '%s'\n",type,command);
  105. +
  106. +	if( n == 2 ){
  107. +		if(strcmpi("server", type) == 0 ){
  108. +			if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 ){
  109. +				runflag = 0;
  110. +			}
  111. +			else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 )
  112. +				ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n");
  113. +		}
  114. +		if( strcmpi("create",type) == 0 )
  115. +		{
  116. +			char username[NAME_LENGTH], password[NAME_LENGTH], md5password[32+1], sex; //23+1 plaintext 32+1 md5
  117. +			bool md5 = 0;
  118. +			if( sscanf(command, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ){
  119. +				ShowWarning("Console: Invalid parameters for '%s'. Usage: %s <username> <password> <sex:F/M>\n", type, type);
  120. +				return 0;
  121. +			}
  122. +			if( login_config.use_md5_passwds ){
  123. +				MD5_String(password,md5password);
  124. +				md5 = 1;
  125. +			}
  126. +			if( mmo_auth_new(username,(md5?md5password:password), TOUPPER(sex), "0.0.0.0") != -1 ){
  127. +				ShowError("Console: Account creation failed.\n");
  128. +				return 0;
  129. +			}
  130. +			ShowStatus("Console: Account '%s' created successfully.\n", username);
  131. +		}
  132. +	}
  133. +	else if( strcmpi("ers_report", type) == 0 ){
  134. +		ers_report();
  135. +	}
  136. +	else if( strcmpi("help", type) == 0 ){
  137. +		ShowInfo("Available commands:\n");
  138. +		ShowInfo("\t server:shutdown => Stops the server.\n");
  139. +		ShowInfo("\t server:alive => Checks if the server is running.\n");
  140. +		ShowInfo("\t ers_report => Displays database usage.\n");
  141. +		ShowInfo("\t create:<username> <password> <sex:M|F> => Creates a new account.\n");
  142. +	}
  143. +	else{ // commands with parameters
  144. +
  145. +
  146. +
  147. +	}
  148. +
  149. +	return 0;
  150. +}
  151. +
  152. +
  153. +///
  154. +/// Char IF
  155. +///
  156. +
  157.  //--------------------------------------------------------------------
  158.  // Packet send to all char-servers, except one (wos: without our self)
  159.  //--------------------------------------------------------------------
  160. @@ -242,7 +318,6 @@
  161.  	chrif_server_init(id);
  162.  }
  163.  
  164. -
  165.  /// Called when the connection to Char Server is disconnected.
  166.  void chrif_on_disconnect(int id)
  167.  {
  168. @@ -250,7 +325,6 @@
  169.  	chrif_server_reset(id);
  170.  }
  171.  
  172. -
  173.  //-----------------------------------------------------
  174.  // periodic ip address synchronization
  175.  //-----------------------------------------------------
  176. @@ -263,684 +337,576 @@
  177.  	return 0;
  178.  }
  179.  
  180. +int login_parsechar_reqauth(int fd, int id,char* ip){
  181. +	if( RFIFOREST(fd) < 23 )
  182. +		return 0;
  183. +	else{
  184. +		struct auth_node* node;
  185. +		int account_id = RFIFOL(fd,2);
  186. +		uint32 login_id1 = RFIFOL(fd,6);
  187. +		uint32 login_id2 = RFIFOL(fd,10);
  188. +		uint8 sex = RFIFOB(fd,14);
  189. +		//uint32 ip_ = ntohl(RFIFOL(fd,15));
  190. +		int request_id = RFIFOL(fd,19);
  191. +		RFIFOSKIP(fd,23);
  192.  
  193. -//-----------------------------------------------------
  194. -// encrypted/unencrypted password check (from eApp)
  195. -//-----------------------------------------------------
  196. -bool check_encrypted(const char* str1, const char* str2, const char* passwd)
  197. -{
  198. -	char tmpstr[64+1], md5str[32+1];
  199. +		node = (struct auth_node*)idb_get(auth_db, account_id);
  200. +		if( runflag == LOGINSERVER_ST_RUNNING &&
  201. +			node != NULL &&
  202. +			node->account_id == account_id &&
  203. +			node->login_id1  == login_id1 &&
  204. +			node->login_id2  == login_id2 &&
  205. +			node->sex        == sex_num2str(sex) /*&&
  206. +			node->ip         == ip_*/ ){// found
  207. +			//ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip);
  208.  
  209. -	safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
  210. -	MD5_String(tmpstr, md5str);
  211. +			// send ack
  212. +			WFIFOHEAD(fd,25);
  213. +			WFIFOW(fd,0) = 0x2713;
  214. +			WFIFOL(fd,2) = account_id;
  215. +			WFIFOL(fd,6) = login_id1;
  216. +			WFIFOL(fd,10) = login_id2;
  217. +			WFIFOB(fd,14) = sex;
  218. +			WFIFOB(fd,15) = 0;// ok
  219. +			WFIFOL(fd,16) = request_id;
  220. +			WFIFOL(fd,20) = node->version;
  221. +			WFIFOB(fd,24) = node->clienttype;
  222. +			WFIFOSET(fd,25);
  223.  
  224. -	return (0==strcmp(passwd, md5str));
  225. +			// each auth entry can only be used once
  226. +			idb_remove(auth_db, account_id);
  227. +		}else{// authentication not found
  228. +			ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip);
  229. +			WFIFOHEAD(fd,25);
  230. +			WFIFOW(fd,0) = 0x2713;
  231. +			WFIFOL(fd,2) = account_id;
  232. +			WFIFOL(fd,6) = login_id1;
  233. +			WFIFOL(fd,10) = login_id2;
  234. +			WFIFOB(fd,14) = sex;
  235. +			WFIFOB(fd,15) = 1;// auth failed
  236. +			WFIFOL(fd,16) = request_id;
  237. +			WFIFOL(fd,20) = 0;
  238. +			WFIFOB(fd,24) = 0;
  239. +			WFIFOSET(fd,25);
  240. +		}
  241. +	}
  242. +	return 1;
  243.  }
  244.  
  245. -bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass)
  246. -{
  247. -	if(passwdenc == 0)
  248. -	{
  249. -		return (0==strcmp(passwd, refpass));
  250. -	}
  251. -	else
  252. -	{
  253. -		// password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
  254. -		// password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
  255. +int login_parsechar_ackusercount(int fd, int id){
  256. +	if( RFIFOREST(fd) < 6 )
  257. +		return 0;
  258. +	else{
  259. +		int users = RFIFOL(fd,2);
  260. +		RFIFOSKIP(fd,6);
  261.  
  262. -		return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) ||
  263. -		       ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd));
  264. +		// how many users on world? (update)
  265. +		if( server[id].users != users ){
  266. +			ShowStatus("set users %s : %d\n", server[id].name, users);
  267. +
  268. +			server[id].users = users;
  269. +		}
  270.  	}
  271. +	return 1;
  272.  }
  273.  
  274. +int login_parsechar_updmail(int fd, int id, char* ip){
  275. +	if (RFIFOREST(fd) < 46)
  276. +		return 0;
  277. +	else{
  278. +		struct mmo_account acc;
  279. +		char email[40];
  280.  
  281. -//-----------------------------------------------------
  282. -// custom timestamp formatting (from eApp)
  283. -//-----------------------------------------------------
  284. -const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
  285. -{
  286. -	size_t len = strftime(str, size, format, localtime(&timestamp));
  287. -	memset(str + len, '\0', size - len);
  288. -	return str;
  289. -}
  290. +		int account_id = RFIFOL(fd,2);
  291. +		safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email);
  292. +		RFIFOSKIP(fd,46);
  293.  
  294. -
  295. -//--------------------------------------------
  296. -// Test to know if an IP come from LAN or WAN.
  297. -//--------------------------------------------
  298. -int lan_subnetcheck(uint32 ip)
  299. -{
  300. -	int i;
  301. -	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  302. -	return ( i < subnet_count ) ? subnet[i].char_ip : 0;
  303. +		if( e_mail_check(email) == 0 )
  304. +			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);
  305. +		else if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "[email protected]") == 0 || acc.email[0] == '\0' )
  306. +			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);
  307. +		else{
  308. +			memcpy(acc.email, email, 40);
  309. +			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);
  310. +			// Save
  311. +			accounts->save(accounts, &acc);
  312. +		}
  313. +	}
  314. +	return 1;
  315.  }
  316.  
  317. -//----------------------------------
  318. -// Reading Lan Support configuration
  319. -//----------------------------------
  320. -int login_lan_config_read(const char *lancfgName)
  321. -{
  322. -	FILE *fp;
  323. -	int line_num = 0;
  324. -	char line[1024], w1[64], w2[64], w3[64], w4[64];
  325. +int login_parsechar_reqaccdata(int fd, int id, char *ip){
  326. +	if( RFIFOREST(fd) < 6 )
  327. +		return 0;
  328. +	else{
  329. +		struct mmo_account acc;
  330. +		time_t expiration_time = 0;
  331. +		char email[40] = "";
  332. +		uint8 char_slots = 0;
  333. +		int group_id = 0;
  334. +		char birthdate[10+1] = "";
  335. +		char pincode[PINCODE_LENGTH+1];
  336. +		int account_id = RFIFOL(fd,2);
  337. +		int cl_version = date2version(PACKETVER);
  338.  
  339. -	if((fp = fopen(lancfgName, "r")) == NULL) {
  340. -		ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
  341. -		return 1;
  342. -	}
  343. +		memset(pincode,0,PINCODE_LENGTH+1);
  344.  
  345. -	while(fgets(line, sizeof(line), fp))
  346. -	{
  347. -		line_num++;
  348. -		if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
  349. -			continue;
  350. +		RFIFOSKIP(fd,6);
  351.  
  352. -		if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4)
  353. -		{
  354. -			ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
  355. -			continue;
  356. +		if( !accounts->load_num(accounts, &acc, account_id) )
  357. +			ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip);
  358. +		else{
  359. +			struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data;
  360. +			safestrncpy(email, acc.email, sizeof(email));
  361. +			expiration_time = acc.expiration_time;
  362. +			group_id = acc.group_id;
  363. +			char_slots = acc.char_slots;
  364. +			safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
  365. +			safestrncpy(pincode, acc.pincode, sizeof(pincode));
  366. +			if(sd) cl_version = sd->version;
  367. +			ShowInfo("login R_0x2716, S_0x2717 version = %d, sd=%d\n",cl_version,sd);
  368.  		}
  369.  
  370. -		if( strcmpi(w1, "subnet") == 0 )
  371. -		{
  372. -			subnet[subnet_count].mask = str2ip(w2);
  373. -			subnet[subnet_count].char_ip = str2ip(w3);
  374. -			subnet[subnet_count].map_ip = str2ip(w4);
  375. -
  376. -			if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
  377. -			{
  378. -				ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
  379. -				continue;
  380. -			}
  381. -
  382. -			subnet_count++;
  383. -		}
  384. +		WFIFOHEAD(fd,73);
  385. +		WFIFOW(fd,0) = 0x2717;
  386. +		WFIFOL(fd,2) = account_id;
  387. +		safestrncpy((char*)WFIFOP(fd,6), email, 40);
  388. +		WFIFOL(fd,46) = (uint32)expiration_time;
  389. +		WFIFOB(fd,50) = (unsigned char)group_id;
  390. +		WFIFOB(fd,51) = char_slots;
  391. +		safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
  392. +		safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
  393. +		WFIFOL(fd,68) = (uint32)acc.pincode_change;
  394. +		WFIFOB(fd,72) = cl_version;
  395. +		WFIFOSET(fd,73);
  396.  	}
  397. +	return 1;
  398. +}
  399.  
  400. -	if( subnet_count > 1 ) /* only useful if there is more than 1 available */
  401. -		ShowStatus("Read information about %d subnetworks.\n", subnet_count);
  402. -
  403. -	fclose(fp);
  404. -	return 0;
  405. +int login_parsechar_keepalive(int fd){
  406. +	RFIFOSKIP(fd,2);
  407. +	WFIFOHEAD(fd,2);
  408. +	WFIFOW(fd,0) = 0x2718;
  409. +	WFIFOSET(fd,2);
  410. +	return 1;
  411.  }
  412.  
  413. -//-----------------------
  414. -// Console Command Parser [Wizputer]
  415. -//-----------------------
  416. -int parse_console(const char* buf){
  417. -	char type[64];
  418. -	char command[64];
  419. -	int n=0;
  420. +// 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  421. +int login_parsechar_reqchangemail(int fd, int id, char* ip){
  422. +	if (RFIFOREST(fd) < 86)
  423. +		return 0;
  424. +	else{
  425. +		struct mmo_account acc;
  426. +		char actual_email[40];
  427. +		char new_email[40];
  428.  
  429. -	if( ( n = sscanf(buf, "%127[^:]:%255[^\n\r]", type, command) ) < 2 ){
  430. -		if((n = sscanf(buf, "%63[^\n]", type))<1) return -1; //nothing to do no arg
  431. -	}
  432. -	if( n != 2 ){ //end string
  433. -		ShowNotice("Type: '%s'\n",type);
  434. -		command[0] = '\0';
  435. -	}
  436. -	else
  437. -		ShowNotice("Type of command: '%s' || Command: '%s'\n",type,command);
  438. +		int account_id = RFIFOL(fd,2);
  439. +		safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40);
  440. +		safestrncpy(new_email, (char*)RFIFOP(fd,46), 40);
  441. +		RFIFOSKIP(fd, 86);
  442.  
  443. -	if( n == 2 ){
  444. -		if(strcmpi("server", type) == 0 ){
  445. -			if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 ){
  446. -				runflag = 0;
  447. -			}
  448. -			else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 )
  449. -				ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n");
  450. +		if( e_mail_check(actual_email) == 0 )
  451. +			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);
  452. +		else if( e_mail_check(new_email) == 0 )
  453. +			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);
  454. +		else if( strcmpi(new_email, "[email protected]") == 0 )
  455. +			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);
  456. +		else if( !accounts->load_num(accounts, &acc, account_id) )
  457. +			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);
  458. +		else if( strcmpi(acc.email, actual_email) != 0 )
  459. +			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);
  460. +		else{
  461. +			safestrncpy(acc.email, new_email, 40);
  462. +			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);
  463. +			// Save
  464. +			accounts->save(accounts, &acc);
  465.  		}
  466. -		if( strcmpi("create",type) == 0 )
  467. -		{
  468. -			char username[NAME_LENGTH], password[NAME_LENGTH], md5password[32+1], sex; //23+1 plaintext 32+1 md5
  469. -			bool md5 = 0;
  470. -			if( sscanf(command, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ){
  471. -				ShowWarning("Console: Invalid parameters for '%s'. Usage: %s <username> <password> <sex:F/M>\n", type, type);
  472. -				return 0;
  473. -			}
  474. -			if( login_config.use_md5_passwds ){
  475. -				MD5_String(password,md5password);
  476. -				md5 = 1;
  477. -			}
  478. -			if( mmo_auth_new(username,(md5?md5password:password), TOUPPER(sex), "0.0.0.0") != -1 ){
  479. -				ShowError("Console: Account creation failed.\n");
  480. -				return 0;
  481. -			}
  482. -			ShowStatus("Console: Account '%s' created successfully.\n", username);
  483. -		}
  484.  	}
  485. -	else if( strcmpi("ers_report", type) == 0 ){
  486. -		ers_report();
  487. -	}
  488. -	else if( strcmpi("help", type) == 0 ){
  489. -		ShowInfo("Available commands:\n");
  490. -		ShowInfo("\t server:shutdown => Stops the server.\n");
  491. -		ShowInfo("\t server:alive => Checks if the server is running.\n");
  492. -		ShowInfo("\t ers_report => Displays database usage.\n");
  493. -		ShowInfo("\t create:<username> <password> <sex:M|F> => Creates a new account.\n");
  494. -	}
  495. -	else{ // commands with parameters
  496. -
  497. -
  498. -
  499. -	}
  500. -
  501. -	return 0;
  502. +	return 1;
  503.  }
  504.  
  505. -
  506. -//--------------------------------
  507. -// Packet parsing for char-servers
  508. -//--------------------------------
  509. -int parse_fromchar(int fd){
  510. -	int j, id;
  511. -	uint32 ipl;
  512. -	char ip[16];
  513. -
  514. -	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  515. -	if( id == ARRAYLENGTH(server) ){// not a char server
  516. -		ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd);
  517. -		set_eof(fd);
  518. -		do_close(fd);
  519. +int login_parsechar_requpdaccstate(int fd, int id, char* ip){
  520. +	if (RFIFOREST(fd) < 10)
  521.  		return 0;
  522. -	}
  523. +	else{
  524. +		struct mmo_account acc;
  525.  
  526. -	if( session[fd]->flag.eof ){
  527. -		do_close(fd);
  528. -		server[id].fd = -1;
  529. -		chrif_on_disconnect(id);
  530. -		return 0;
  531. -	}
  532. +		int account_id = RFIFOL(fd,2);
  533. +		unsigned int state = RFIFOL(fd,6);
  534. +		RFIFOSKIP(fd,10);
  535.  
  536. -	ipl = server[id].ip;
  537. -	ip2str(ipl, ip);
  538. +		if( !accounts->load_num(accounts, &acc, account_id) )
  539. +			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);
  540. +		else if( acc.state == state )
  541. +			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);
  542. +		else{
  543. +			ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip);
  544.  
  545. -	while( RFIFOREST(fd) >= 2 ){
  546. -		uint16 command = RFIFOW(fd,0);
  547. +			acc.state = state;
  548. +			// Save
  549. +			accounts->save(accounts, &acc);
  550.  
  551. -		switch( command ){
  552. -
  553. -		case 0x2712: // request from char-server to authenticate an account
  554. -			if( RFIFOREST(fd) < 23 )
  555. -				return 0;
  556. -			else{
  557. -				struct auth_node* node;
  558. -				int account_id = RFIFOL(fd,2);
  559. -				uint32 login_id1 = RFIFOL(fd,6);
  560. -				uint32 login_id2 = RFIFOL(fd,10);
  561. -				uint8 sex = RFIFOB(fd,14);
  562. -				//uint32 ip_ = ntohl(RFIFOL(fd,15));
  563. -				int request_id = RFIFOL(fd,19);
  564. -				RFIFOSKIP(fd,23);
  565. -
  566. -				node = (struct auth_node*)idb_get(auth_db, account_id);
  567. -				if( runflag == LOGINSERVER_ST_RUNNING &&
  568. -					node != NULL &&
  569. -					node->account_id == account_id &&
  570. -					node->login_id1  == login_id1 &&
  571. -					node->login_id2  == login_id2 &&
  572. -					node->sex        == sex_num2str(sex) /*&&
  573. -					node->ip         == ip_*/ ){// found
  574. -					//ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip);
  575. -
  576. -					// send ack
  577. -					WFIFOHEAD(fd,25);
  578. -					WFIFOW(fd,0) = 0x2713;
  579. -					WFIFOL(fd,2) = account_id;
  580. -					WFIFOL(fd,6) = login_id1;
  581. -					WFIFOL(fd,10) = login_id2;
  582. -					WFIFOB(fd,14) = sex;
  583. -					WFIFOB(fd,15) = 0;// ok
  584. -					WFIFOL(fd,16) = request_id;
  585. -					WFIFOL(fd,20) = node->version;
  586. -					WFIFOB(fd,24) = node->clienttype;
  587. -					WFIFOSET(fd,25);
  588. -
  589. -					// each auth entry can only be used once
  590. -					idb_remove(auth_db, account_id);
  591. -				}else{// authentication not found
  592. -					ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip);
  593. -					WFIFOHEAD(fd,25);
  594. -					WFIFOW(fd,0) = 0x2713;
  595. -					WFIFOL(fd,2) = account_id;
  596. -					WFIFOL(fd,6) = login_id1;
  597. -					WFIFOL(fd,10) = login_id2;
  598. -					WFIFOB(fd,14) = sex;
  599. -					WFIFOB(fd,15) = 1;// auth failed
  600. -					WFIFOL(fd,16) = request_id;
  601. -					WFIFOL(fd,20) = 0;
  602. -					WFIFOB(fd,24) = 0;
  603. -					WFIFOSET(fd,25);
  604. -				}
  605. +			// notify other servers
  606. +			if (state != 0){
  607. +				uint8 buf[11];
  608. +				WBUFW(buf,0) = 0x2731;
  609. +				WBUFL(buf,2) = account_id;
  610. +				WBUFB(buf,6) = 0; // 0: change of state, 1: ban
  611. +				WBUFL(buf,7) = state; // status or final date of a banishment
  612. +				charif_sendallwos(-1, buf, 11);
  613.  			}
  614. -		break;
  615. +		}
  616. +	}
  617. +	return 1;
  618. +}
  619.  
  620. -		case 0x2714:
  621. -			if( RFIFOREST(fd) < 6 )
  622. -				return 0;
  623. -			else{
  624. -				int users = RFIFOL(fd,2);
  625. -				RFIFOSKIP(fd,6);
  626. +int login_parsechar_reqbanacc(int fd, int id, char* ip){
  627. +	if (RFIFOREST(fd) < 18)
  628. +		return 0;
  629. +	else{
  630. +		struct mmo_account acc;
  631.  
  632. -				// how many users on world? (update)
  633. -				if( server[id].users != users ){
  634. -					ShowStatus("set users %s : %d\n", server[id].name, users);
  635. +		int account_id = RFIFOL(fd,2);
  636. +		int year = (short)RFIFOW(fd,6);
  637. +		int month = (short)RFIFOW(fd,8);
  638. +		int mday = (short)RFIFOW(fd,10);
  639. +		int hour = (short)RFIFOW(fd,12);
  640. +		int min = (short)RFIFOW(fd,14);
  641. +		int sec = (short)RFIFOW(fd,16);
  642. +		RFIFOSKIP(fd,18);
  643.  
  644. -					server[id].users = users;
  645. -				}
  646. -			}
  647. -		break;
  648. -
  649. -		case 0x2715: // request from char server to change e-email from default "[email protected]"
  650. -			if (RFIFOREST(fd) < 46)
  651. -				return 0;
  652. +		if( !accounts->load_num(accounts, &acc, account_id) )
  653. +			ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  654. +		else{
  655. +			time_t timestamp;
  656. +			struct tm *tmtime;
  657. +			if (acc.unban_time == 0 || acc.unban_time < time(NULL))
  658. +				timestamp = time(NULL); // new ban
  659. +			else
  660. +				timestamp = acc.unban_time; // add to existing ban
  661. +			tmtime = localtime(&timestamp);
  662. +			tmtime->tm_year = tmtime->tm_year + year;
  663. +			tmtime->tm_mon  = tmtime->tm_mon + month;
  664. +			tmtime->tm_mday = tmtime->tm_mday + mday;
  665. +			tmtime->tm_hour = tmtime->tm_hour + hour;
  666. +			tmtime->tm_min  = tmtime->tm_min + min;
  667. +			tmtime->tm_sec  = tmtime->tm_sec + sec;
  668. +			timestamp = mktime(tmtime);
  669. +			if (timestamp == -1)
  670. +				ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip);
  671. +			else if( timestamp <= time(NULL) || timestamp == 0 )
  672. +				ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip);
  673.  			else{
  674. -				struct mmo_account acc;
  675. -				char email[40];
  676. +				uint8 buf[11];
  677. +				char tmpstr[24];
  678. +				timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format);
  679. +				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);
  680.  
  681. -				int account_id = RFIFOL(fd,2);
  682. -				safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email);
  683. -				RFIFOSKIP(fd,46);
  684. +				acc.unban_time = timestamp;
  685.  
  686. -				if( e_mail_check(email) == 0 )
  687. -					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);
  688. -				else if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "[email protected]") == 0 || acc.email[0] == '\0' )
  689. -					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);
  690. -				else{
  691. -					memcpy(acc.email, email, 40);
  692. -					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);
  693. -					// Save
  694. -					accounts->save(accounts, &acc);
  695. -				}
  696. -			}
  697. -		break;
  698. +				// Save
  699. +				accounts->save(accounts, &acc);
  700.  
  701. -		case 0x2716: // request account data
  702. -			if( RFIFOREST(fd) < 6 )
  703. -				return 0;
  704. -			else{
  705. -				struct mmo_account acc;
  706. -				time_t expiration_time = 0;
  707. -				char email[40] = "";
  708. -				uint8 char_slots = 0;
  709. -				int group_id = 0;
  710. -				char birthdate[10+1] = "";
  711. -				char pincode[PINCODE_LENGTH+1];
  712. -				int account_id = RFIFOL(fd,2);
  713. -
  714. -				memset(pincode,0,PINCODE_LENGTH+1);
  715. -
  716. -				RFIFOSKIP(fd,6);
  717. -
  718. -				if( !accounts->load_num(accounts, &acc, account_id) )
  719. -					ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip);
  720. -				else{
  721. -					safestrncpy(email, acc.email, sizeof(email));
  722. -					expiration_time = acc.expiration_time;
  723. -					group_id = acc.group_id;
  724. -					char_slots = acc.char_slots;
  725. -					safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
  726. -					safestrncpy(pincode, acc.pincode, sizeof(pincode));
  727. -				}
  728. -
  729. -				WFIFOHEAD(fd,72);
  730. -				WFIFOW(fd,0) = 0x2717;
  731. -				WFIFOL(fd,2) = account_id;
  732. -				safestrncpy((char*)WFIFOP(fd,6), email, 40);
  733. -				WFIFOL(fd,46) = (uint32)expiration_time;
  734. -				WFIFOB(fd,50) = (unsigned char)group_id;
  735. -				WFIFOB(fd,51) = char_slots;
  736. -				safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
  737. -				safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
  738. -				WFIFOL(fd,68) = (uint32)acc.pincode_change;
  739. -				WFIFOSET(fd,72);
  740. +				WBUFW(buf,0) = 0x2731;
  741. +				WBUFL(buf,2) = account_id;
  742. +				WBUFB(buf,6) = 1; // 0: change of status, 1: ban
  743. +				WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment
  744. +				charif_sendallwos(-1, buf, 11);
  745.  			}
  746. -		break;
  747. +		}
  748. +	}
  749. +	return 1;
  750. +}
  751.  
  752. -		case 0x2719: // ping request from charserver
  753. -			RFIFOSKIP(fd,2);
  754. +int login_parsechar_reqchgsex(int fd, int id, char* ip){
  755. +	if( RFIFOREST(fd) < 6 )
  756. +		return 0;
  757. +	else{
  758. +		struct mmo_account acc;
  759.  
  760. -			WFIFOHEAD(fd,2);
  761. -			WFIFOW(fd,0) = 0x2718;
  762. -			WFIFOSET(fd,2);
  763. -		break;
  764. +		int account_id = RFIFOL(fd,2);
  765. +		RFIFOSKIP(fd,6);
  766.  
  767. -		// Map server send information to change an email of an account via char-server
  768. -		case 0x2722:	// 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  769. -			if (RFIFOREST(fd) < 86)
  770. -				return 0;
  771. -			else{
  772. -				struct mmo_account acc;
  773. -				char actual_email[40];
  774. -				char new_email[40];
  775. +		if( !accounts->load_num(accounts, &acc, account_id) )
  776. +			ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  777. +		else if( acc.sex == 'S' )
  778. +			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);
  779. +		else{
  780. +			unsigned char buf[7];
  781. +			char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender
  782.  
  783. -				int account_id = RFIFOL(fd,2);
  784. -				safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40);
  785. -				safestrncpy(new_email, (char*)RFIFOP(fd,46), 40);
  786. -				RFIFOSKIP(fd, 86);
  787. +			ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip);
  788.  
  789. -				if( e_mail_check(actual_email) == 0 )
  790. -					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);
  791. -				else if( e_mail_check(new_email) == 0 )
  792. -					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);
  793. -				else if( strcmpi(new_email, "[email protected]") == 0 )
  794. -					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);
  795. -				else if( !accounts->load_num(accounts, &acc, account_id) )
  796. -					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);
  797. -				else if( strcmpi(acc.email, actual_email) != 0 )
  798. -					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);
  799. -				else{
  800. -					safestrncpy(acc.email, new_email, 40);
  801. -					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);
  802. -					// Save
  803. -					accounts->save(accounts, &acc);
  804. -				}
  805. -			}
  806. -		break;
  807. +			acc.sex = sex;
  808. +			// Save
  809. +			accounts->save(accounts, &acc);
  810.  
  811. -		case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server)
  812. -			if (RFIFOREST(fd) < 10)
  813. -				return 0;
  814. -			else{
  815. -				struct mmo_account acc;
  816. +			// announce to other servers
  817. +			WBUFW(buf,0) = 0x2723;
  818. +			WBUFL(buf,2) = account_id;
  819. +			WBUFB(buf,6) = sex_str2num(sex);
  820. +			charif_sendallwos(-1, buf, 7);
  821. +		}
  822. +	}
  823. +	return 1;
  824. +}
  825.  
  826. -				int account_id = RFIFOL(fd,2);
  827. -				unsigned int state = RFIFOL(fd,6);
  828. -				RFIFOSKIP(fd,10);
  829. +int login_parsechar_updreg2(int fd, int id, char* ip){
  830. +	int j;
  831. +	if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) )
  832. +		return 0;
  833. +	else{
  834. +		struct mmo_account acc;
  835.  
  836. -				if( !accounts->load_num(accounts, &acc, account_id) )
  837. -					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);
  838. -				else if( acc.state == state )
  839. -					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);
  840. -				else{
  841. -					ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip);
  842. +		int account_id = RFIFOL(fd,4);
  843.  
  844. -					acc.state = state;
  845. -					// Save
  846. -					accounts->save(accounts, &acc);
  847. -
  848. -					// notify other servers
  849. -					if (state != 0){
  850. -						uint8 buf[11];
  851. -						WBUFW(buf,0) = 0x2731;
  852. -						WBUFL(buf,2) = account_id;
  853. -						WBUFB(buf,6) = 0; // 0: change of state, 1: ban
  854. -						WBUFL(buf,7) = state; // status or final date of a banishment
  855. -						charif_sendallwos(-1, buf, 11);
  856. -					}
  857. -				}
  858. +		if( !accounts->load_num(accounts, &acc, account_id) )
  859. +			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);
  860. +		else{
  861. +			int len;
  862. +			int p;
  863. +			ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  864. +			for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ){
  865. +				sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len);
  866. +				acc.account_reg2[j].str[len]='\0';
  867. +				p +=len+1; //+1 to skip the '\0' between strings.
  868. +				sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len);
  869. +				acc.account_reg2[j].value[len]='\0';
  870. +				p +=len+1;
  871. +				remove_control_chars(acc.account_reg2[j].str);
  872. +				remove_control_chars(acc.account_reg2[j].value);
  873.  			}
  874. -		break;
  875. +			acc.account_reg2_num = j;
  876.  
  877. -		case 0x2725: // Receiving of map-server via char-server a ban request
  878. -			if (RFIFOREST(fd) < 18)
  879. -				return 0;
  880. -			else{
  881. -				struct mmo_account acc;
  882. +			// Save
  883. +			accounts->save(accounts, &acc);
  884.  
  885. -				int account_id = RFIFOL(fd,2);
  886. -				int year = (short)RFIFOW(fd,6);
  887. -				int month = (short)RFIFOW(fd,8);
  888. -				int mday = (short)RFIFOW(fd,10);
  889. -				int hour = (short)RFIFOW(fd,12);
  890. -				int min = (short)RFIFOW(fd,14);
  891. -				int sec = (short)RFIFOW(fd,16);
  892. -				RFIFOSKIP(fd,18);
  893. +			// Sending information towards the other char-servers.
  894. +			RFIFOW(fd,0) = 0x2729;// reusing read buffer
  895. +			charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2));
  896. +		}
  897. +		RFIFOSKIP(fd,RFIFOW(fd,2));
  898. +	}
  899. +	return 1;
  900. +}
  901.  
  902. -				if( !accounts->load_num(accounts, &acc, account_id) )
  903. -					ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  904. -				else{
  905. -					time_t timestamp;
  906. -					struct tm *tmtime;
  907. -					if (acc.unban_time == 0 || acc.unban_time < time(NULL))
  908. -						timestamp = time(NULL); // new ban
  909. -					else
  910. -						timestamp = acc.unban_time; // add to existing ban
  911. -					tmtime = localtime(&timestamp);
  912. -					tmtime->tm_year = tmtime->tm_year + year;
  913. -					tmtime->tm_mon  = tmtime->tm_mon + month;
  914. -					tmtime->tm_mday = tmtime->tm_mday + mday;
  915. -					tmtime->tm_hour = tmtime->tm_hour + hour;
  916. -					tmtime->tm_min  = tmtime->tm_min + min;
  917. -					tmtime->tm_sec  = tmtime->tm_sec + sec;
  918. -					timestamp = mktime(tmtime);
  919. -					if (timestamp == -1)
  920. -						ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip);
  921. -					else if( timestamp <= time(NULL) || timestamp == 0 )
  922. -						ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip);
  923. -					else{
  924. -						uint8 buf[11];
  925. -						char tmpstr[24];
  926. -						timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format);
  927. -						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);
  928. +int login_parsechar_requnbanacc(int fd, int id, char* ip){
  929. +	if( RFIFOREST(fd) < 6 )
  930. +		return 0;
  931. +	else{
  932. +		struct mmo_account acc;
  933.  
  934. -						acc.unban_time = timestamp;
  935. +		int account_id = RFIFOL(fd,2);
  936. +		RFIFOSKIP(fd,6);
  937.  
  938. -						// Save
  939. -						accounts->save(accounts, &acc);
  940. +		if( !accounts->load_num(accounts, &acc, account_id) )
  941. +			ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  942. +		else if( acc.unban_time == 0 )
  943. +			ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip);
  944. +		else{
  945. +			ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  946. +			acc.unban_time = 0;
  947. +			accounts->save(accounts, &acc);
  948. +		}
  949. +	}
  950. +	return 1;
  951. +}
  952.  
  953. -						WBUFW(buf,0) = 0x2731;
  954. -						WBUFL(buf,2) = account_id;
  955. -						WBUFB(buf,6) = 1; // 0: change of status, 1: ban
  956. -						WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment
  957. -						charif_sendallwos(-1, buf, 11);
  958. -					}
  959. -				}
  960. -			}
  961. -		break;
  962. +int login_parsechar_setacconline(int fd, int id){
  963. +	if( RFIFOREST(fd) < 6 )
  964. +		return 0;
  965. +	add_online_user(id, RFIFOL(fd,2));
  966. +	RFIFOSKIP(fd,6);
  967. +	return 1;
  968. +}
  969.  
  970. -		case 0x2727: // Change of sex (sex is reversed)
  971. -			if( RFIFOREST(fd) < 6 )
  972. -				return 0;
  973. -			else{
  974. -				struct mmo_account acc;
  975. +int login_parsechar_setaccoffline(int fd, int id){
  976. +	if( RFIFOREST(fd) < 6 )
  977. +		return 0;
  978. +	remove_online_user(RFIFOL(fd,2));
  979. +	RFIFOSKIP(fd,6);
  980. +	return 1;
  981. +}
  982.  
  983. -				int account_id = RFIFOL(fd,2);
  984. -				RFIFOSKIP(fd,6);
  985. -
  986. -				if( !accounts->load_num(accounts, &acc, account_id) )
  987. -					ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  988. -				else if( acc.sex == 'S' )
  989. -					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);
  990. -				else{
  991. -					unsigned char buf[7];
  992. -					char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender
  993. -
  994. -					ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip);
  995. -
  996. -					acc.sex = sex;
  997. -					// Save
  998. -					accounts->save(accounts, &acc);
  999. -
  1000. -					// announce to other servers
  1001. -					WBUFW(buf,0) = 0x2723;
  1002. -					WBUFL(buf,2) = account_id;
  1003. -					WBUFB(buf,6) = sex_str2num(sex);
  1004. -					charif_sendallwos(-1, buf, 7);
  1005. -				}
  1006. +int login_parsechar_updonlinedb(int fd, int id){
  1007. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1008. +		return 0;
  1009. +	else{
  1010. +		struct online_login_data *p;
  1011. +		int aid;
  1012. +		uint32 i, users;
  1013. +		online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first
  1014. +		users = RFIFOW(fd,4);
  1015. +		for (i = 0; i < users; i++) {
  1016. +			aid = RFIFOL(fd,6+i*4);
  1017. +			p = idb_ensure(online_db, aid, create_online_user);
  1018. +			p->char_server = id;
  1019. +			if (p->waiting_disconnect != INVALID_TIMER){
  1020. +				delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
  1021. +				p->waiting_disconnect = INVALID_TIMER;
  1022.  			}
  1023. -		break;
  1024. +		}
  1025. +		RFIFOSKIP(fd,RFIFOW(fd,2));
  1026. +	}
  1027. +	return 1;
  1028. +}
  1029.  
  1030. -		case 0x2728:	// We receive account_reg2 from a char-server, and we send them to other map-servers.
  1031. -			if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) )
  1032. -				return 0;
  1033. -			else{
  1034. -				struct mmo_account acc;
  1035. +int login_parsechar_reqacc2reg(int fd, int id){
  1036. +	int j;
  1037. +	if (RFIFOREST(fd) < 10)
  1038. +		return 0;
  1039. +	else{
  1040. +		struct mmo_account acc;
  1041. +		size_t off;
  1042.  
  1043. -				int account_id = RFIFOL(fd,4);
  1044. +		int account_id = RFIFOL(fd,2);
  1045. +		int char_id = RFIFOL(fd,6);
  1046. +		RFIFOSKIP(fd,10);
  1047.  
  1048. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1049. -					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);
  1050. -				else{
  1051. -					int len;
  1052. -					int p;
  1053. -					ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  1054. -					for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ){
  1055. -						sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len);
  1056. -						acc.account_reg2[j].str[len]='\0';
  1057. -						p +=len+1; //+1 to skip the '\0' between strings.
  1058. -						sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len);
  1059. -						acc.account_reg2[j].value[len]='\0';
  1060. -						p +=len+1;
  1061. -						remove_control_chars(acc.account_reg2[j].str);
  1062. -						remove_control_chars(acc.account_reg2[j].value);
  1063. -					}
  1064. -					acc.account_reg2_num = j;
  1065. +		WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg));
  1066. +		WFIFOW(fd,0) = 0x2729;
  1067. +		WFIFOL(fd,4) = account_id;
  1068. +		WFIFOL(fd,8) = char_id;
  1069. +		WFIFOB(fd,12) = 1; //Type 1 for Account2 registry
  1070.  
  1071. -					// Save
  1072. -					accounts->save(accounts, &acc);
  1073. -
  1074. -					// Sending information towards the other char-servers.
  1075. -					RFIFOW(fd,0) = 0x2729;// reusing read buffer
  1076. -					charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2));
  1077. +		off = 13;
  1078. +		if( accounts->load_num(accounts, &acc, account_id) ){
  1079. +			for( j = 0; j < acc.account_reg2_num; j++ ){
  1080. +				if( acc.account_reg2[j].str[0] != '\0' ){
  1081. +					off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place.
  1082. +					off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1;
  1083.  				}
  1084. -				RFIFOSKIP(fd,RFIFOW(fd,2));
  1085.  			}
  1086. -		break;
  1087. +		}
  1088.  
  1089. -		case 0x272a:	// Receiving of map-server via char-server an unban request
  1090. -			if( RFIFOREST(fd) < 6 )
  1091. -				return 0;
  1092. -			else{
  1093. -				struct mmo_account acc;
  1094. +		WFIFOW(fd,2) = (uint16)off;
  1095. +		WFIFOSET(fd,WFIFOW(fd,2));
  1096. +	}
  1097. +	return 1;
  1098. +}
  1099.  
  1100. -				int account_id = RFIFOL(fd,2);
  1101. -				RFIFOSKIP(fd,6);
  1102. +int login_parsechar_updcharip(int fd, int id){
  1103. +	if( RFIFOREST(fd) < 6 )
  1104. +		return 0;
  1105. +	server[id].ip = ntohl(RFIFOL(fd,2));
  1106. +	ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip));
  1107. +	RFIFOSKIP(fd,6);
  1108. +	return 1;
  1109. +}
  1110.  
  1111. -				if( !accounts->load_num(accounts, &acc, account_id) )
  1112. -					ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
  1113. -				else if( acc.unban_time == 0 )
  1114. -					ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip);
  1115. -				else{
  1116. -					ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip);
  1117. -					acc.unban_time = 0;
  1118. -					accounts->save(accounts, &acc);
  1119. -				}
  1120. -			}
  1121. -		break;
  1122. +int login_parsechar_setalloffline(int fd, int id){
  1123. +	ShowInfo("Setting accounts from char-server %d offline.\n", id);
  1124. +	online_db->foreach(online_db, online_db_setoffline, id);
  1125. +	RFIFOSKIP(fd,2);
  1126. +	return 1;
  1127. +}
  1128.  
  1129. -		case 0x272b:    // Set account_id to online [Wizputer]
  1130. -			if( RFIFOREST(fd) < 6 )
  1131. -				return 0;
  1132. -			add_online_user(id, RFIFOL(fd,2));
  1133. -			RFIFOSKIP(fd,6);
  1134. -		break;
  1135. +int login_parsechar_updpincode(int fd, int id){
  1136. +	if( RFIFOREST(fd) < 11 )
  1137. +		return 0;
  1138. +	else{
  1139. +		struct mmo_account acc;
  1140.  
  1141. -		case 0x272c:   // Set account_id to offline [Wizputer]
  1142. -			if( RFIFOREST(fd) < 6 )
  1143. -				return 0;
  1144. -			remove_online_user(RFIFOL(fd,2));
  1145. -			RFIFOSKIP(fd,6);
  1146. -		break;
  1147. +		if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
  1148. +			strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 );
  1149. +			acc.pincode_change = time( NULL );
  1150. +			accounts->save(accounts, &acc);
  1151. +		}
  1152.  
  1153. -		case 0x272d:	// Receive list of all online accounts. [Skotlex]
  1154. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1155. -				return 0;
  1156. -			else{
  1157. -				struct online_login_data *p;
  1158. -				int aid;
  1159. -				uint32 i, users;
  1160. -				online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first
  1161. -				users = RFIFOW(fd,4);
  1162. -				for (i = 0; i < users; i++) {
  1163. -					aid = RFIFOL(fd,6+i*4);
  1164. -					p = idb_ensure(online_db, aid, create_online_user);
  1165. -					p->char_server = id;
  1166. -					if (p->waiting_disconnect != INVALID_TIMER){
  1167. -						delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
  1168. -						p->waiting_disconnect = INVALID_TIMER;
  1169. -					}
  1170. -				}
  1171. +		RFIFOSKIP(fd,11);
  1172. +	}
  1173. +	return 1;
  1174. +}
  1175.  
  1176. -				RFIFOSKIP(fd,RFIFOW(fd,2));
  1177. -			}
  1178. -		break;
  1179. +int login_parsechar_pincode_authfail(int fd, int id){
  1180. +	if( RFIFOREST(fd) < 6 )
  1181. +		return 0;
  1182. +	else{
  1183. +		struct mmo_account acc;
  1184. +		if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
  1185. +			struct online_login_data* ld;
  1186.  
  1187. -		case 0x272e: //Request account_reg2 for a character.
  1188. -			if (RFIFOREST(fd) < 10)
  1189. -				return 0;
  1190. -			else{
  1191. -				struct mmo_account acc;
  1192. -				size_t off;
  1193. +			ld = (struct online_login_data*)idb_get(online_db,acc.account_id);
  1194.  
  1195. -				int account_id = RFIFOL(fd,2);
  1196. -				int char_id = RFIFOL(fd,6);
  1197. -				RFIFOSKIP(fd,10);
  1198. -
  1199. -				WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg));
  1200. -				WFIFOW(fd,0) = 0x2729;
  1201. -				WFIFOL(fd,4) = account_id;
  1202. -				WFIFOL(fd,8) = char_id;
  1203. -				WFIFOB(fd,12) = 1; //Type 1 for Account2 registry
  1204. -
  1205. -				off = 13;
  1206. -				if( accounts->load_num(accounts, &acc, account_id) ){
  1207. -					for( j = 0; j < acc.account_reg2_num; j++ ){
  1208. -						if( acc.account_reg2[j].str[0] != '\0' ){
  1209. -							off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place.
  1210. -							off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1;
  1211. -						}
  1212. -					}
  1213. -				}
  1214. -
  1215. -				WFIFOW(fd,2) = (uint16)off;
  1216. -				WFIFOSET(fd,WFIFOW(fd,2));
  1217. -			}
  1218. -		break;
  1219. -
  1220. -		case 0x2736: // WAN IP update from char-server
  1221. -			if( RFIFOREST(fd) < 6 )
  1222. +			if( ld == NULL )
  1223.  				return 0;
  1224. -			server[id].ip = ntohl(RFIFOL(fd,2));
  1225. -			ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip));
  1226. -			RFIFOSKIP(fd,6);
  1227. -		break;
  1228.  
  1229. -		case 0x2737: //Request to set all offline.
  1230. -			ShowInfo("Setting accounts from char-server %d offline.\n", id);
  1231. -			online_db->foreach(online_db, online_db_setoffline, id);
  1232. -			RFIFOSKIP(fd,2);
  1233. -		break;
  1234. +			login_log( host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed" );
  1235. +		}
  1236. +		remove_online_user(acc.account_id);
  1237. +		RFIFOSKIP(fd,6);
  1238. +	}
  1239. +	return 1;
  1240. +}
  1241.  
  1242. -		case 0x2738: //Change PIN Code for a account
  1243. -			if( RFIFOREST(fd) < 11 )
  1244. -				return 0;
  1245. -			else{
  1246. -				struct mmo_account acc;
  1247. +//--------------------------------
  1248. +// Packet parsing for char-servers
  1249. +//--------------------------------
  1250. +int parse_fromchar(int fd){
  1251. +	int id;
  1252. +	uint32 ipl;
  1253. +	char ip[16];
  1254.  
  1255. -				if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
  1256. -					strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 );
  1257. -					acc.pincode_change = time( NULL );
  1258. -					accounts->save(accounts, &acc);
  1259. -				}
  1260. +	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  1261. +	if( id == ARRAYLENGTH(server) ){// not a char server
  1262. +		ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd);
  1263. +		set_eof(fd);
  1264. +		do_close(fd);
  1265. +		return 0;
  1266. +	}
  1267.  
  1268. -				RFIFOSKIP(fd,11);
  1269. -			}
  1270. -		break;
  1271. +	if( session[fd]->flag.eof ){
  1272. +		do_close(fd);
  1273. +		server[id].fd = -1;
  1274. +		chrif_on_disconnect(id);
  1275. +		return 0;
  1276. +	}
  1277.  
  1278. -		case 0x2739: // PIN Code was entered wrong too often
  1279. -			if( RFIFOREST(fd) < 6 )
  1280. -				return 0;
  1281. -			else{
  1282. -				struct mmo_account acc;
  1283. +	ipl = server[id].ip;
  1284. +	ip2str(ipl, ip);
  1285.  
  1286. -				if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
  1287. -					struct online_login_data* ld;
  1288. +	while( RFIFOREST(fd) >= 2 ){
  1289. +		uint16 command = RFIFOW(fd,0);
  1290.  
  1291. -					ld = (struct online_login_data*)idb_get(online_db,acc.account_id);
  1292. -
  1293. -					if( ld == NULL )
  1294. -						return 0;
  1295. -
  1296. -					login_log( host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed" );
  1297. -				}
  1298. -
  1299. -				remove_online_user(acc.account_id);
  1300. -
  1301. -				RFIFOSKIP(fd,6);
  1302. -			}
  1303. -		break;
  1304. -
  1305. +		switch( command ){
  1306. +		// request from char-server to authenticate an account
  1307. +		case 0x2712: login_parsechar_reqauth(fd, id, ip); break;
  1308. +		//update user cout
  1309. +		case 0x2714: login_parsechar_ackusercount(fd, id); break;
  1310. +		// request from char server to change e-email from default "[email protected]"
  1311. +		case 0x2715: login_parsechar_updmail(fd, id, ip); break;
  1312. +		// request account data
  1313. +		case 0x2716: login_parsechar_reqaccdata(fd, id, ip); break;
  1314. +		// ping request from charserver
  1315. +		case 0x2719: login_parsechar_keepalive(fd); break;
  1316. +		// Map server send information to change an email of an account via char-server
  1317. +		case 0x2722: login_parsechar_reqchangemail(fd,id,ip); break;
  1318. +		// Receiving an account state update request from a map-server (relayed via char-server)
  1319. +		case 0x2724: login_parsechar_requpdaccstate(fd,id,ip); break;
  1320. +		// Receiving of map-server via char-server a ban request
  1321. +		case 0x2725: login_parsechar_reqbanacc(fd,id,ip); break;
  1322. +		// Change of sex (sex is reversed)
  1323. +		case 0x2727: login_parsechar_reqchgsex(fd,id,ip); break;
  1324. +		// We receive account_reg2 from a char-server, and we send them to other map-servers.
  1325. +		case 0x2728: login_parsechar_updreg2(fd,id,ip); break;
  1326. +		// Receiving of map-server via char-server an unban request
  1327. +		case 0x272a: login_parsechar_requnbanacc(fd,id,ip); break;
  1328. +		// Set account_id to online [Wizputer]
  1329. +		case 0x272b: login_parsechar_setacconline(fd,id); break;
  1330. +		// Set account_id to offline [Wizputer]
  1331. +		case 0x272c: login_parsechar_setaccoffline(fd,id); break;
  1332. +		// Receive list of all online accounts. [Skotlex]
  1333. +		case 0x272d: login_parsechar_updonlinedb(fd,id); break;
  1334. +		//Request account_reg2 for a character
  1335. +		case 0x272e: login_parsechar_reqacc2reg(fd,id); break;
  1336. +		// WAN IP update from char-server
  1337. +		case 0x2736: login_parsechar_updcharip(fd,id); break;
  1338. +		//Request to set all offline.
  1339. +		case 0x2737: login_parsechar_setalloffline(fd,id); break;
  1340. +		//Change PIN Code for a account
  1341. +		case 0x2738: login_parsechar_updpincode(fd,id); break;
  1342. +		// PIN Code was entered wrong too often
  1343. +		case 0x2739: login_parsechar_pincode_authfail(fd,id); break;
  1344.  		default:
  1345.  			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
  1346.  			set_eof(fd);
  1347. @@ -952,6 +918,39 @@
  1348.  }
  1349.  
  1350.  
  1351. +///
  1352. +/// Client IF
  1353. +///
  1354. +
  1355. +//-----------------------------------------------------
  1356. +// encrypted/unencrypted password check (from eApp)
  1357. +//-----------------------------------------------------
  1358. +bool check_encrypted(const char* str1, const char* str2, const char* passwd)
  1359. +{
  1360. +	char tmpstr[64+1], md5str[32+1];
  1361. +
  1362. +	safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
  1363. +	MD5_String(tmpstr, md5str);
  1364. +
  1365. +	return (0==strcmp(passwd, md5str));
  1366. +}
  1367. +
  1368. +bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass)
  1369. +{
  1370. +	if(passwdenc == 0)
  1371. +	{
  1372. +		return (0==strcmp(passwd, refpass));
  1373. +	}
  1374. +	else
  1375. +	{
  1376. +		// password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
  1377. +		// password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
  1378. +
  1379. +		return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) ||
  1380. +		       ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd));
  1381. +	}
  1382. +}
  1383. +
  1384.  //-------------------------------------
  1385.  // Make new account
  1386.  //-------------------------------------
  1387. @@ -1101,7 +1100,9 @@
  1388.  		}
  1389.  
  1390.  		while( node ) {
  1391. -			if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) {
  1392. +			ShowInfo("login mmo_auth, node_groupid=%d, acc_groupid=%d node_hash=%s client_hash=%d\n",
  1393. +				node->group_id,acc.group_id,node->hash,sd->client_hash);
  1394. +			if( node->group_id <= acc.group_id && (memcmp(node->hash, sd->client_hash, 16) == 0 || strcmp(node->hash,"any")==0 ) ){
  1395.  				match = true;
  1396.  				break;
  1397.  			}
  1398. @@ -1270,10 +1271,8 @@
  1399.  
  1400.  	{
  1401.  		struct online_login_data* data;
  1402. -
  1403.  		// mark client as 'online'
  1404.  		data = add_online_user(-1, sd->account_id);
  1405. -
  1406.  		// schedule deletion of this node
  1407.  		data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0);
  1408.  	}
  1409. @@ -1323,108 +1322,61 @@
  1410.  	if( result == 1 && login_config.dynamic_pass_failure_ban )
  1411.  		ipban_log(ip); // log failed password attempt
  1412.  
  1413. -#if PACKETVER >= 20120000 /* not sure when this started */
  1414. -	WFIFOHEAD(fd,26);
  1415. -	WFIFOW(fd,0) = 0x83e;
  1416. -	WFIFOL(fd,2) = result;
  1417. -	if( result != 6 )
  1418. -		memset(WFIFOP(fd,6), '\0', 20);
  1419. -	else { // 6 = Your are Prohibited to log in until %s
  1420. -		struct mmo_account acc;
  1421. -		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
  1422. -		timestamp2string((char*)WFIFOP(fd,6), 20, unban_time, login_config.date_format);
  1423. +	if( sd->version >= date2version(20120000) ){ /* not sure when this started */
  1424. +		WFIFOHEAD(fd,26);
  1425. +		WFIFOW(fd,0) = 0x83e;
  1426. +		WFIFOL(fd,2) = result;
  1427. +		if( result != 6 )
  1428. +			memset(WFIFOP(fd,6), '\0', 20);
  1429. +		else { // 6 = Your are Prohibited to log in until %s
  1430. +			struct mmo_account acc;
  1431. +			time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
  1432. +			timestamp2string((char*)WFIFOP(fd,6), 20, unban_time, login_config.date_format);
  1433. +		}
  1434. +		WFIFOSET(fd,26);
  1435.  	}
  1436. -	WFIFOSET(fd,26);
  1437. -#else
  1438. -	WFIFOHEAD(fd,23);
  1439. -	WFIFOW(fd,0) = 0x6a;
  1440. -	WFIFOB(fd,2) = (uint8)result;
  1441. -	if( result != 6 )
  1442. -		memset(WFIFOP(fd,3), '\0', 20);
  1443. -	else { // 6 = Your are Prohibited to log in until %s
  1444. -		struct mmo_account acc;
  1445. -		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
  1446. -		timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format);
  1447. +	else {
  1448. +		WFIFOHEAD(fd,23);
  1449. +		WFIFOW(fd,0) = 0x6a;
  1450. +		WFIFOB(fd,2) = (uint8)result;
  1451. +		if( result != 6 )
  1452. +			memset(WFIFOP(fd,3), '\0', 20);
  1453. +		else { // 6 = Your are Prohibited to log in until %s
  1454. +			struct mmo_account acc;
  1455. +			time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
  1456. +			timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format);
  1457. +		}
  1458. +		WFIFOSET(fd,23);
  1459.  	}
  1460. -	WFIFOSET(fd,23);
  1461. -#endif
  1462.  }
  1463.  
  1464. +//0x200 <account.userid>.24B.
  1465. +int login_parse_keepalive(int fd){
  1466. +	if (RFIFOREST(fd) < 26)
  1467. +		return 0;
  1468. +	RFIFOSKIP(fd,26);
  1469. +	return 1;
  1470. +}
  1471.  
  1472. -//----------------------------------------------------------------------------------------
  1473. -// Default packet parsing (normal players or char-server connection requests)
  1474. -//----------------------------------------------------------------------------------------
  1475. -int parse_login(int fd)
  1476. -{
  1477. -	struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data;
  1478. -	int result;
  1479. -
  1480. -	char ip[16];
  1481. -	uint32 ipl = session[fd]->client_addr;
  1482. -	ip2str(ipl, ip);
  1483. -
  1484. -	if( session[fd]->flag.eof )
  1485. -	{
  1486. -		ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip);
  1487. -		do_close(fd);
  1488. +// S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6)
  1489. +int login_parse_updclhash(int fd, struct login_session_data *sd){
  1490. +	if (RFIFOREST(fd) < 18)
  1491.  		return 0;
  1492. -	}
  1493. +	sd->has_client_hash = 1;
  1494. +	memcpy(sd->client_hash, RFIFOP(fd, 2), 16);
  1495. +	RFIFOSKIP(fd,18);
  1496. +	return 1;
  1497. +}
  1498.  
  1499. -	if( sd == NULL )
  1500. -	{
  1501. -		// Perform ip-ban check
  1502. -		if( login_config.ipban && ipban_check(ipl) )
  1503. +// S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
  1504. +// S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
  1505. +// S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
  1506. +// S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
  1507. +// 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"))
  1508. +// S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
  1509. +// S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
  1510. +int login_parse_reqauth(int fd, struct login_session_data *sd, int command, char* ip){
  1511.  		{
  1512. -			ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip);
  1513. -			login_log(ipl, "unknown", -3, "ip banned");
  1514. -			WFIFOHEAD(fd,23);
  1515. -			WFIFOW(fd,0) = 0x6a;
  1516. -			WFIFOB(fd,2) = 3; // 3 = Rejected from Server
  1517. -			WFIFOSET(fd,23);
  1518. -			set_eof(fd);
  1519. -			return 0;
  1520. -		}
  1521. -
  1522. -		// create a session for this new connection
  1523. -		CREATE(session[fd]->session_data, struct login_session_data, 1);
  1524. -		sd = (struct login_session_data*)session[fd]->session_data;
  1525. -		sd->fd = fd;
  1526. -	}
  1527. -
  1528. -	while( RFIFOREST(fd) >= 2 )
  1529. -	{
  1530. -		uint16 command = RFIFOW(fd,0);
  1531. -
  1532. -		switch( command )
  1533. -		{
  1534. -
  1535. -		case 0x0200:		// New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
  1536. -			if (RFIFOREST(fd) < 26)
  1537. -				return 0;
  1538. -			RFIFOSKIP(fd,26);
  1539. -		break;
  1540. -
  1541. -		// client md5 hash (binary)
  1542. -		case 0x0204: // S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6)
  1543. -			if (RFIFOREST(fd) < 18)
  1544. -				return 0;
  1545. -
  1546. -			sd->has_client_hash = 1;
  1547. -			memcpy(sd->client_hash, RFIFOP(fd, 2), 16);
  1548. -
  1549. -			RFIFOSKIP(fd,18);
  1550. -		break;
  1551. -
  1552. -		// request client login (raw password)
  1553. -		case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
  1554. -		case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
  1555. -		case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
  1556. -		// request client login (md5-hashed password)
  1557. -		case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
  1558. -		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"))
  1559. -		case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
  1560. -		case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
  1561. -		{
  1562.  			size_t packet_len = RFIFOREST(fd);
  1563.  
  1564.  			if( (command == 0x0064 && packet_len < 55)
  1565. @@ -1437,6 +1389,7 @@
  1566.  				return 0;
  1567.  		}
  1568.  		{
  1569. +			int result;
  1570.  			uint32 version;
  1571.  			char username[NAME_LENGTH];
  1572.  			char password[NAME_LENGTH];
  1573. @@ -1512,88 +1465,156 @@
  1574.  			else
  1575.  				login_auth_failed(sd, result);
  1576.  		}
  1577. -		break;
  1578. +	return 1;
  1579. +}
  1580.  
  1581. -		case 0x01db:	// Sending request of the coding key
  1582. -			RFIFOSKIP(fd,2);
  1583. +int login_parse_reqkey(int fd, struct login_session_data *sd){
  1584. +	RFIFOSKIP(fd,2);
  1585. +	{
  1586. +		memset(sd->md5key, '\0', sizeof(sd->md5key));
  1587. +		sd->md5keylen = (uint16)(12 + rnd() % 4);
  1588. +		MD5_Salt(sd->md5keylen, sd->md5key);
  1589. +
  1590. +		WFIFOHEAD(fd,4 + sd->md5keylen);
  1591. +		WFIFOW(fd,0) = 0x01dc;
  1592. +		WFIFOW(fd,2) = 4 + sd->md5keylen;
  1593. +		memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen);
  1594. +		WFIFOSET(fd,WFIFOW(fd,2));
  1595. +	}
  1596. +	return 1;
  1597. +}
  1598. +
  1599. +int login_parse_reqcharconnec(int fd, struct login_session_data *sd, char* ip){
  1600. +	if (RFIFOREST(fd) < 86)
  1601. +		return 0;
  1602. +	{
  1603. +		int result;
  1604. +		char server_name[20];
  1605. +		char message[256];
  1606. +		uint32 server_ip;
  1607. +		uint16 server_port;
  1608. +		uint16 type;
  1609. +		uint16 new_;
  1610. +
  1611. +		safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH);
  1612. +		safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH);
  1613. +		if( login_config.use_md5_passwds )
  1614. +			MD5_String(sd->passwd, sd->passwd);
  1615. +		sd->passwdenc = 0;
  1616. +		sd->version = login_config.client_version_to_connect; // hack to skip version check
  1617. +		server_ip = ntohl(RFIFOL(fd,54));
  1618. +		server_port = ntohs(RFIFOW(fd,58));
  1619. +		safestrncpy(server_name, (char*)RFIFOP(fd,60), 20);
  1620. +		type = RFIFOW(fd,82);
  1621. +		new_ = RFIFOW(fd,84);
  1622. +		RFIFOSKIP(fd,86);
  1623. +
  1624. +		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);
  1625. +		sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port);
  1626. +		login_log(session[fd]->client_addr, sd->userid, 100, message);
  1627. +
  1628. +		result = mmo_auth(sd, true);
  1629. +		if( runflag == LOGINSERVER_ST_RUNNING &&
  1630. +			result == -1 &&
  1631. +			sd->sex == 'S' &&
  1632. +			sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) &&
  1633. +			!session_isValid(server[sd->account_id].fd) )
  1634.  		{
  1635. -			memset(sd->md5key, '\0', sizeof(sd->md5key));
  1636. -			sd->md5keylen = (uint16)(12 + rnd() % 4);
  1637. -			MD5_Salt(sd->md5keylen, sd->md5key);
  1638. +			ShowStatus("Connection of the char-server '%s' accepted.\n", server_name);
  1639. +			safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name));
  1640. +			server[sd->account_id].fd = fd;
  1641. +			server[sd->account_id].ip = server_ip;
  1642. +			server[sd->account_id].port = server_port;
  1643. +			server[sd->account_id].users = 0;
  1644. +			server[sd->account_id].type = type;
  1645. +			server[sd->account_id].new_ = new_;
  1646.  
  1647. -			WFIFOHEAD(fd,4 + sd->md5keylen);
  1648. -			WFIFOW(fd,0) = 0x01dc;
  1649. -			WFIFOW(fd,2) = 4 + sd->md5keylen;
  1650. -			memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen);
  1651. -			WFIFOSET(fd,WFIFOW(fd,2));
  1652. +			session[fd]->func_parse = parse_fromchar;
  1653. +			session[fd]->flag.server = 1;
  1654. +			realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  1655. +
  1656. +			// send connection success
  1657. +			WFIFOHEAD(fd,3);
  1658. +			WFIFOW(fd,0) = 0x2711;
  1659. +			WFIFOB(fd,2) = 0;
  1660. +			WFIFOSET(fd,3);
  1661.  		}
  1662. -		break;
  1663. -
  1664. -		case 0x2710:	// Connection request of a char-server
  1665. -			if (RFIFOREST(fd) < 86)
  1666. -				return 0;
  1667. +		else
  1668.  		{
  1669. -			char server_name[20];
  1670. -			char message[256];
  1671. -			uint32 server_ip;
  1672. -			uint16 server_port;
  1673. -			uint16 type;
  1674. -			uint16 new_;
  1675. +			ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name);
  1676. +			WFIFOHEAD(fd,3);
  1677. +			WFIFOW(fd,0) = 0x2711;
  1678. +			WFIFOB(fd,2) = 3;
  1679. +			WFIFOSET(fd,3);
  1680. +		}
  1681. +	}
  1682. +	return 1;
  1683. +}
  1684.  
  1685. -			safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH);
  1686. -			safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH);
  1687. -			if( login_config.use_md5_passwds )
  1688. -				MD5_String(sd->passwd, sd->passwd);
  1689. -			sd->passwdenc = 0;
  1690. -			sd->version = login_config.client_version_to_connect; // hack to skip version check
  1691. -			server_ip = ntohl(RFIFOL(fd,54));
  1692. -			server_port = ntohs(RFIFOW(fd,58));
  1693. -			safestrncpy(server_name, (char*)RFIFOP(fd,60), 20);
  1694. -			type = RFIFOW(fd,82);
  1695. -			new_ = RFIFOW(fd,84);
  1696. -			RFIFOSKIP(fd,86);
  1697. +//----------------------------------------------------------------------------------------
  1698. +// Default packet parsing (normal players or char-server connection requests)
  1699. +//----------------------------------------------------------------------------------------
  1700. +int parse_login(int fd)
  1701. +{
  1702. +	struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data;
  1703.  
  1704. -			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);
  1705. -			sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port);
  1706. -			login_log(session[fd]->client_addr, sd->userid, 100, message);
  1707. +	char ip[16];
  1708. +	uint32 ipl = session[fd]->client_addr;
  1709. +	ip2str(ipl, ip);
  1710.  
  1711. -			result = mmo_auth(sd, true);
  1712. -			if( runflag == LOGINSERVER_ST_RUNNING &&
  1713. -				result == -1 &&
  1714. -				sd->sex == 'S' &&
  1715. -				sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) &&
  1716. -				!session_isValid(server[sd->account_id].fd) )
  1717. -			{
  1718. -				ShowStatus("Connection of the char-server '%s' accepted.\n", server_name);
  1719. -				safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name));
  1720. -				server[sd->account_id].fd = fd;
  1721. -				server[sd->account_id].ip = server_ip;
  1722. -				server[sd->account_id].port = server_port;
  1723. -				server[sd->account_id].users = 0;
  1724. -				server[sd->account_id].type = type;
  1725. -				server[sd->account_id].new_ = new_;
  1726. +	if( session[fd]->flag.eof )
  1727. +	{
  1728. +		ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip);
  1729. +		do_close(fd);
  1730. +		return 0;
  1731. +	}
  1732.  
  1733. -				session[fd]->func_parse = parse_fromchar;
  1734. -				session[fd]->flag.server = 1;
  1735. -				realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  1736. -
  1737. -				// send connection success
  1738. -				WFIFOHEAD(fd,3);
  1739. -				WFIFOW(fd,0) = 0x2711;
  1740. -				WFIFOB(fd,2) = 0;
  1741. -				WFIFOSET(fd,3);
  1742. -			}
  1743. -			else
  1744. -			{
  1745. -				ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name);
  1746. -				WFIFOHEAD(fd,3);
  1747. -				WFIFOW(fd,0) = 0x2711;
  1748. -				WFIFOB(fd,2) = 3;
  1749. -				WFIFOSET(fd,3);
  1750. -			}
  1751. +	if( sd == NULL )
  1752. +	{
  1753. +		// Perform ip-ban check
  1754. +		if( login_config.ipban && ipban_check(ipl) )
  1755. +		{
  1756. +			ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip);
  1757. +			login_log(ipl, "unknown", -3, "ip banned");
  1758. +			WFIFOHEAD(fd,23);
  1759. +			WFIFOW(fd,0) = 0x6a;
  1760. +			WFIFOB(fd,2) = 3; // 3 = Rejected from Server
  1761. +			WFIFOSET(fd,23);
  1762. +			set_eof(fd);
  1763. +			return 0;
  1764.  		}
  1765. -		return 0; // processing will continue elsewhere
  1766.  
  1767. +		// create a session for this new connection
  1768. +		CREATE(session[fd]->session_data, struct login_session_data, 1);
  1769. +		sd = (struct login_session_data*)session[fd]->session_data;
  1770. +		sd->fd = fd;
  1771. +	}
  1772. +
  1773. +	while( RFIFOREST(fd) >= 2 )
  1774. +	{
  1775. +		uint16 command = RFIFOW(fd,0);
  1776. +
  1777. +		switch( command )
  1778. +		{
  1779. +		// New alive packet: used to verify if client is always alive.
  1780. +		case 0x0200: login_parse_keepalive(fd); break;
  1781. +		// client md5 hash (binary)
  1782. +		case 0x0204: login_parse_updclhash(fd,sd); break;
  1783. +
  1784. +		// request client login (raw password)
  1785. +		case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
  1786. +		case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
  1787. +		case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
  1788. +		// request client login (md5-hashed password)
  1789. +		case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
  1790. +		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"))
  1791. +		case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
  1792. +		case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
  1793. +			login_parse_reqauth(fd,  sd, command, ip); break;
  1794. +		// Sending request of the coding key
  1795. +		case 0x01db: login_parse_reqkey(fd, sd); break;
  1796. +		// Connection request of a char-server
  1797. +		case 0x2710: login_parse_reqcharconnec(fd,sd, ip); 	return 0; // processing will continue elsewhere
  1798.  		default:
  1799.  			ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command);
  1800.  			set_eof(fd);
  1801. @@ -1604,7 +1625,9 @@
  1802.  	return 0;
  1803.  }
  1804.  
  1805. -
  1806. +/*
  1807. + * Init default configuration
  1808. + */
  1809.  void login_set_defaults()
  1810.  {
  1811.  	login_config.login_ip = INADDR_ANY;
  1812. @@ -1620,7 +1643,8 @@
  1813.  	login_config.group_id_to_connect = -1;
  1814.  	login_config.min_group_id_to_connect = -1;
  1815.  	login_config.check_client_version = false;
  1816. -	login_config.client_version_to_connect = 20;
  1817. +	login_config.client_version_to_connect = date2version(PACKETVER); //20120410 => 30
  1818. +	ShowInfo("loginconfig: client_version_to_connect = %d\n",login_config.client_version_to_connect);
  1819.  
  1820.  	login_config.ipban = true;
  1821.  	login_config.dynamic_pass_failure_ban = true;
  1822. @@ -1635,6 +1659,55 @@
  1823.  	login_config.client_hash_nodes = NULL;
  1824.  }
  1825.  
  1826. +//----------------------------------
  1827. +// Reading Lan Support configuration
  1828. +//----------------------------------
  1829. +int login_lan_config_read(const char *lancfgName)
  1830. +{
  1831. +	FILE *fp;
  1832. +	int line_num = 0;
  1833. +	char line[1024], w1[64], w2[64], w3[64], w4[64];
  1834. +
  1835. +	if((fp = fopen(lancfgName, "r")) == NULL) {
  1836. +		ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
  1837. +		return 1;
  1838. +	}
  1839. +
  1840. +	while(fgets(line, sizeof(line), fp))
  1841. +	{
  1842. +		line_num++;
  1843. +		if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
  1844. +			continue;
  1845. +
  1846. +		if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4)
  1847. +		{
  1848. +			ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
  1849. +			continue;
  1850. +		}
  1851. +
  1852. +		if( strcmpi(w1, "subnet") == 0 )
  1853. +		{
  1854. +			subnet[subnet_count].mask = str2ip(w2);
  1855. +			subnet[subnet_count].char_ip = str2ip(w3);
  1856. +			subnet[subnet_count].map_ip = str2ip(w4);
  1857. +
  1858. +			if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
  1859. +			{
  1860. +				ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
  1861. +				continue;
  1862. +			}
  1863. +
  1864. +			subnet_count++;
  1865. +		}
  1866. +	}
  1867. +
  1868. +	if( subnet_count > 1 ) /* only useful if there is more than 1 available */
  1869. +		ShowStatus("Read information about %d subnetworks.\n", subnet_count);
  1870. +
  1871. +	fclose(fp);
  1872. +	return 0;
  1873. +}
  1874. +
  1875.  //-----------------------------------
  1876.  // Reading main configuration file
  1877.  //-----------------------------------
  1878. Index: src/char/char.c
  1879. ===================================================================
  1880. --- src/char/char.c	(revision 17365)
  1881. +++ src/char/char.c	(working copy)
  1882. @@ -33,10 +33,9 @@
  1883.  #include <stdlib.h>
  1884.  #include <malloc.h>
  1885.  
  1886. -#define MAX_STARTITEM 32
  1887. -#define CHAR_MAX_MSG 300
  1888. -static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
  1889. -
  1890. +// <editor-fold defaultstate="collapsed" desc="db_tablename">
  1891. +int db_use_sqldbs;
  1892. +char db_path[1024] = "db";
  1893.  char char_db[256] = "char";
  1894.  char scdata_db[256] = "sc_data";
  1895.  char cart_db[256] = "cart_inventory";
  1896. @@ -67,16 +66,17 @@
  1897.  char mercenary_db[256] = "mercenary";
  1898.  char mercenary_owner_db[256] = "mercenary_owner";
  1899.  char ragsrvinfo_db[256] = "ragsrvinfo";
  1900. +// </editor-fold>
  1901.  
  1902. +
  1903.  // show loading/saving messages
  1904.  int save_log = 1;
  1905.  
  1906.  static DBMap* char_db_; // int char_id -> struct mmo_charstatus*
  1907.  
  1908. -char db_path[1024] = "db";
  1909. +#define CHAR_MAX_MSG 300
  1910. +static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
  1911.  
  1912. -int db_use_sqldbs;
  1913. -
  1914.  struct mmo_map_server {
  1915.  	int fd;
  1916.  	uint32 ip;
  1917. @@ -115,103 +115,90 @@
  1918.  int log_char = 1;	// loggin char or not [devil]
  1919.  int log_inter = 1;	// loggin inter or not [devil]
  1920.  
  1921. -// Advanced subnet check [LuzZza]
  1922. -struct s_subnet {
  1923. -	uint32 mask;
  1924. -	uint32 char_ip;
  1925. -	uint32 map_ip;
  1926. -} subnet[16];
  1927. -int subnet_count = 0;
  1928. +// check for exit signal
  1929. +// 0 is saving complete
  1930. +// other is char_id
  1931. +unsigned int save_flag = 0;
  1932. +// Initial position (it's possible to set it in conf file)
  1933. +struct point start_point = { 0, 53, 111 };
  1934. +int console = 0;
  1935. +int max_connect_user = -1;
  1936. +int gm_allow_group = -1;
  1937. +int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  1938. +int start_zeny = 0;
  1939. +int guild_exp_rate = 100;
  1940.  
  1941. -struct char_session_data {
  1942. -	bool auth; // whether the session is authed or not
  1943. -	int account_id, login_id1, login_id2, sex;
  1944. -	int found_char[MAX_CHARS]; // ids of chars on this account
  1945. -	char email[40]; // e-mail (default: [email protected]) by [Yor]
  1946. -	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  1947. -	int group_id; // permission
  1948. -	uint8 char_slots;
  1949. -	uint32 version;
  1950. -	uint8 clienttype;
  1951. -	char new_name[NAME_LENGTH];
  1952. -	char birthdate[10+1];  // YYYY-MM-DD
  1953. -	// Pincode system
  1954. -	char pincode[PINCODE_LENGTH+1];
  1955. -	uint32 pincode_seed;
  1956. -	time_t pincode_change;
  1957. -	uint16 pincode_try;
  1958. -	// Addon system
  1959. -	unsigned int char_moves[MAX_CHARS]; // character moves left
  1960. -};
  1961. -
  1962. +#define MAX_STARTITEM 32
  1963.  struct startitem {
  1964.  	int nameid; //Item ID
  1965.  	int amount; //Number of items
  1966.  	int pos; //Position (for auto-equip)
  1967.  } start_items[MAX_STARTITEM+1];
  1968.  
  1969. -int max_connect_user = -1;
  1970. -int gm_allow_group = -1;
  1971. -int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  1972. -int start_zeny = 0;
  1973. -int guild_exp_rate = 100;
  1974. -
  1975.  // Pincode system
  1976. -#define PINCODE_OK 0
  1977. -#define PINCODE_ASK 1
  1978. -#define PINCODE_NOTSET 2
  1979. -#define PINCODE_EXPIRED 3
  1980. -#define PINCODE_NEW 4
  1981. -#define PINCODE_PASSED 7
  1982. -#define	PINCODE_WRONG 8
  1983. -
  1984. +enum pincode_state {
  1985. +	PINCODE_OK = 0,
  1986. +	PINCODE_ASK,
  1987. +	PINCODE_NOTSET,
  1988. +	PINCODE_EXPIRED,
  1989. +	PINCODE_NEW,
  1990. +	PINCODE_PASSED,
  1991. +	PINCODE_WRONG,
  1992. +	PINCODE_MAXSTATE
  1993. +};
  1994.  bool pincode_enabled = true;
  1995.  int pincode_changetime = 0;
  1996.  int pincode_maxtry = 3;
  1997.  bool pincode_force = true;
  1998.  
  1999. -void pincode_check( int fd, struct char_session_data* sd );
  2000. -void pincode_change( int fd, struct char_session_data* sd );
  2001. -void pincode_setnew( int fd, struct char_session_data* sd );
  2002. -void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state );
  2003. -void pincode_notifyLoginPinUpdate( int account_id, char* pin );
  2004. -void pincode_notifyLoginPinError( int account_id );
  2005. -void pincode_decrypt( uint32 userSeed, char* pin );
  2006. -int pincode_compare( int fd, struct char_session_data* sd, char* pin );
  2007. -
  2008.  // Addon system
  2009.  bool char_move_enabled = true;
  2010.  bool char_movetoused = true;
  2011.  bool char_moves_unlimited = false;
  2012.  
  2013. -void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to );
  2014. -void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason );
  2015. -
  2016.  //Custom limits for the fame lists. [Skotlex]
  2017.  int fame_list_size_chemist = MAX_FAME_LIST;
  2018.  int fame_list_size_smith = MAX_FAME_LIST;
  2019.  int fame_list_size_taekwon = MAX_FAME_LIST;
  2020. -
  2021.  // Char-server-side stored fame lists [DracoRPG]
  2022.  struct fame_list smith_fame_list[MAX_FAME_LIST];
  2023.  struct fame_list chemist_fame_list[MAX_FAME_LIST];
  2024.  struct fame_list taekwon_fame_list[MAX_FAME_LIST];
  2025.  
  2026. -// check for exit signal
  2027. -// 0 is saving complete
  2028. -// other is char_id
  2029. -unsigned int save_flag = 0;
  2030.  
  2031. -// Initial position (it's possible to set it in conf file)
  2032. -struct point start_point = { 0, 53, 111 };
  2033. +// Advanced subnet check [LuzZza]
  2034. +struct s_subnet {
  2035. +	uint32 mask;
  2036. +	uint32 char_ip;
  2037. +	uint32 map_ip;
  2038. +} subnet[16];
  2039. +int subnet_count = 0;
  2040.  
  2041. -int console = 0;
  2042. +struct char_session_data {
  2043. +	bool auth; // whether the session is authed or not
  2044. +	int account_id, login_id1, login_id2, sex;
  2045. +	int found_char[MAX_CHARS]; // ids of chars on this account
  2046. +	char email[40]; // e-mail (default: [email protected]) by [Yor]
  2047. +	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  2048. +	int group_id; // permission
  2049. +	uint8 char_slots;
  2050. +	uint32 version;
  2051. +	uint8 clienttype;
  2052. +	char new_name[NAME_LENGTH];
  2053. +	char birthdate[10+1];  // YYYY-MM-DD
  2054. +	// Pincode system
  2055. +	char pincode[PINCODE_LENGTH+1];
  2056. +	uint32 pincode_seed;
  2057. +	time_t pincode_change;
  2058. +	uint16 pincode_try;
  2059. +	// Addon system
  2060. +	unsigned int char_moves[MAX_CHARS]; // character moves left
  2061. +};
  2062.  
  2063.  //-----------------------------------------------------
  2064.  // Auth database
  2065.  //-----------------------------------------------------
  2066.  #define AUTH_TIMEOUT 30000
  2067. -
  2068.  struct auth_node {
  2069.  	int account_id;
  2070.  	int char_id;
  2071. @@ -223,13 +210,11 @@
  2072.  	int group_id;
  2073.  	unsigned changing_mapservers : 1;
  2074.  };
  2075. -
  2076.  static DBMap* auth_db; // int account_id -> struct auth_node*
  2077.  
  2078.  //-----------------------------------------------------
  2079.  // Online User Database
  2080.  //-----------------------------------------------------
  2081. -
  2082.  struct online_char_data {
  2083.  	int account_id;
  2084.  	int char_id;
  2085. @@ -238,8 +223,12 @@
  2086.  	short server; // -2: unknown server, -1: not connected, 0+: id of server
  2087.  	bool pincode_success;
  2088.  };
  2089. +static DBMap* online_char_db; // int account_id -> struct online_char_data*
  2090.  
  2091. -static DBMap* online_char_db; // int account_id -> struct online_char_data*
  2092. +
  2093. +int parse_char(int fd);
  2094. +int parse_fromlogin(int fd);
  2095. +
  2096.  static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
  2097.  int delete_char_sql(int char_id);
  2098.  
  2099. @@ -1951,8 +1940,12 @@
  2100.  }
  2101.  
  2102.  //struct PACKET_CH_CHARLIST_REQ { 0x0 short PacketType}
  2103. -void char_parse_req_charlist(int fd, struct char_session_data* sd){
  2104. +int char_parse_req_charlist(int fd, struct char_session_data* sd){
  2105. +	if( RFIFOREST(fd) < 2 )
  2106. +		return 0;
  2107. +	RFIFOSKIP(fd,2);
  2108.  	mmo_char_send099d(fd,sd);
  2109. +	return 1;
  2110.  }
  2111.  
  2112.  //----------------------------------------
  2113. @@ -2001,13 +1994,12 @@
  2114.  
  2115.  void mmo_char_send(int fd, struct char_session_data* sd){
  2116.  	ShowInfo("sd->version = %d\n",sd->version);
  2117. -#if PACKETVER >= 20130000
  2118. +	if(sd->version > 34){
  2119.  		mmo_char_send082d(fd,sd);
  2120.  		char_charlist_notify(fd,sd);
  2121.  		char_block_character(fd,sd);
  2122. -#endif
  2123. -	//@FIXME dump from kro doesn't show 6b transmission
  2124. -	mmo_char_send006b(fd,sd);
  2125. +	}
  2126. +	mmo_char_send006b(fd,sd); //@FIXME dump from kro doesn't show 6b transmission
  2127.  }
  2128.  
  2129.  int char_married(int pl1, int pl2)
  2130. @@ -2184,369 +2176,6 @@
  2131.  		ShowStatus("Awaiting maps from map-server.\n");
  2132.  }
  2133.  
  2134. -
  2135. -int parse_fromlogin(int fd) {
  2136. -	struct char_session_data* sd = NULL;
  2137. -	int i;
  2138. -
  2139. -	// only process data from the login-server
  2140. -	if( fd != login_fd ) {
  2141. -		ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
  2142. -		do_close(fd);
  2143. -		return 0;
  2144. -	}
  2145. -
  2146. -	if( session[fd]->flag.eof ) {
  2147. -		do_close(fd);
  2148. -		login_fd = -1;
  2149. -		loginif_on_disconnect();
  2150. -		return 0;
  2151. -	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
  2152. -		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
  2153. -			set_eof(fd);
  2154. -			return 0;
  2155. -		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
  2156. -			WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
  2157. -			WFIFOW(fd,0) = 0x2719;
  2158. -			WFIFOSET(fd,2);
  2159. -
  2160. -			session[fd]->flag.ping = 2;
  2161. -		}
  2162. -	}
  2163. -
  2164. -	sd = (struct char_session_data*)session[fd]->session_data;
  2165. -
  2166. -	while(RFIFOREST(fd) >= 2) {
  2167. -		uint16 command = RFIFOW(fd,0);
  2168. -
  2169. -		switch( command )
  2170. -		{
  2171. -
  2172. -		// acknowledgement of connect-to-loginserver request
  2173. -		case 0x2711:
  2174. -			if (RFIFOREST(fd) < 3)
  2175. -				return 0;
  2176. -
  2177. -			if (RFIFOB(fd,2)) {
  2178. -				//printf("connect login server error : %d\n", RFIFOB(fd,2));
  2179. -				ShowError("Can not connect to login-server.\n");
  2180. -				ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  2181. -				ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
  2182. -				ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
  2183. -				set_eof(fd);
  2184. -				return 0;
  2185. -			} else {
  2186. -				ShowStatus("Connected to login-server (connection #%d).\n", fd);
  2187. -				loginif_on_ready();
  2188. -			}
  2189. -			RFIFOSKIP(fd,3);
  2190. -		break;
  2191. -
  2192. -		// acknowledgement of account authentication request
  2193. -		case 0x2713:
  2194. -			if (RFIFOREST(fd) < 25)
  2195. -				return 0;
  2196. -		{
  2197. -			int account_id = RFIFOL(fd,2);
  2198. -			uint32 login_id1 = RFIFOL(fd,6);
  2199. -			uint32 login_id2 = RFIFOL(fd,10);
  2200. -			uint8 sex = RFIFOB(fd,14);
  2201. -			uint8 result = RFIFOB(fd,15);
  2202. -			int request_id = RFIFOL(fd,16);
  2203. -			uint32 version = RFIFOL(fd,20);
  2204. -			uint8 clienttype = RFIFOB(fd,24);
  2205. -			RFIFOSKIP(fd,25);
  2206. -
  2207. -			if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
  2208. -				!sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
  2209. -			{
  2210. -				int client_fd = request_id;
  2211. -				sd->version = version;
  2212. -				sd->clienttype = clienttype;
  2213. -				switch( result )
  2214. -				{
  2215. -				case 0:// ok
  2216. -					char_auth_ok(client_fd, sd);
  2217. -					break;
  2218. -				case 1:// auth failed
  2219. -					WFIFOHEAD(client_fd,3);
  2220. -					WFIFOW(client_fd,0) = 0x6c;
  2221. -					WFIFOB(client_fd,2) = 0;// rejected from server
  2222. -					WFIFOSET(client_fd,3);
  2223. -					break;
  2224. -				}
  2225. -			}
  2226. -		}
  2227. -		break;
  2228. -
  2229. -		case 0x2717: // account data
  2230. -			if (RFIFOREST(fd) < 72)
  2231. -				return 0;
  2232. -
  2233. -			// find the authenticated session with this account id
  2234. -			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) );
  2235. -			if( i < fd_max )
  2236. -			{
  2237. -				int server_id;
  2238. -				memcpy(sd->email, RFIFOP(fd,6), 40);
  2239. -				sd->expiration_time = (time_t)RFIFOL(fd,46);
  2240. -				sd->group_id = RFIFOB(fd,50);
  2241. -				sd->char_slots = RFIFOB(fd,51);
  2242. -				if( sd->char_slots > MAX_CHARS ) {
  2243. -					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);
  2244. -					sd->char_slots = MAX_CHARS;/* cap to maximum */
  2245. -				} else if ( !sd->char_slots )/* no value aka 0 in sql */
  2246. -					sd->char_slots = MAX_CHARS;/* cap to maximum */
  2247. -				safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
  2248. -				safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
  2249. -				sd->pincode_change = (time_t)RFIFOL(fd,68);
  2250. -				ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
  2251. -				// continued from char_auth_ok...
  2252. -				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
  2253. -					(max_connect_user == 0 && sd->group_id != gm_allow_group) ||
  2254. -					( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
  2255. -					// refuse connection (over populated)
  2256. -					WFIFOHEAD(i,3);
  2257. -					WFIFOW(i,0) = 0x6c;
  2258. -					WFIFOW(i,2) = 0;
  2259. -					WFIFOSET(i,3);
  2260. -				} else {
  2261. -					// send characters to player
  2262. -					mmo_char_send(i, sd);
  2263. -#if PACKETVER >=  20110309
  2264. -					if( pincode_enabled ){
  2265. -						// PIN code system enabled
  2266. -						if( strlen( sd->pincode ) <= 0 ){
  2267. -							// No PIN code has been set yet
  2268. -							if( pincode_force ){
  2269. -								pincode_sendstate( i, sd, PINCODE_NEW );
  2270. -							}else{
  2271. -								pincode_sendstate( i, sd, PINCODE_PASSED );
  2272. -							}
  2273. -						}else{
  2274. -							if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
  2275. -								struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
  2276. -
  2277. -								if( node != NULL && node->pincode_success ){
  2278. -									// User has already passed the check
  2279. -									pincode_sendstate( i, sd, PINCODE_PASSED );
  2280. -								}else{
  2281. -									// Ask user for his PIN code
  2282. -									pincode_sendstate( i, sd, PINCODE_ASK );
  2283. -								}
  2284. -							}else{
  2285. -								// User hasnt changed his PIN code too long
  2286. -								pincode_sendstate( i, sd, PINCODE_EXPIRED );
  2287. -							}
  2288. -						}
  2289. -					}else{
  2290. -						// PIN code system disabled
  2291. -						pincode_sendstate( i, sd, PINCODE_OK );
  2292. -					}
  2293. -#endif
  2294. -				}
  2295. -			}
  2296. -			RFIFOSKIP(fd,72);
  2297. -		break;
  2298. -
  2299. -		// login-server alive packet
  2300. -		case 0x2718:
  2301. -			if (RFIFOREST(fd) < 2)
  2302. -				return 0;
  2303. -			RFIFOSKIP(fd,2);
  2304. -			session[fd]->flag.ping = 0;
  2305. -		break;
  2306. -
  2307. -		// changesex reply
  2308. -		case 0x2723:
  2309. -			if (RFIFOREST(fd) < 7)
  2310. -				return 0;
  2311. -		{
  2312. -			unsigned char buf[7];
  2313. -
  2314. -			int acc = RFIFOL(fd,2);
  2315. -			int sex = RFIFOB(fd,6);
  2316. -			RFIFOSKIP(fd,7);
  2317. -
  2318. -			if( acc > 0 )
  2319. -			{// TODO: Is this even possible?
  2320. -				int char_id[MAX_CHARS];
  2321. -				int class_[MAX_CHARS];
  2322. -				int guild_id[MAX_CHARS];
  2323. -				int num;
  2324. -				char* data;
  2325. -
  2326. -				struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
  2327. -				if( node != NULL )
  2328. -					node->sex = sex;
  2329. -
  2330. -				// get characters
  2331. -				if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
  2332. -					Sql_ShowDebug(sql_handle);
  2333. -				for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
  2334. -				{
  2335. -					Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
  2336. -					Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
  2337. -					Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
  2338. -				}
  2339. -				num = i;
  2340. -				for( i = 0; i < num; ++i )
  2341. -				{
  2342. -					if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
  2343. -						class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
  2344. -						class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
  2345. -						class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
  2346. -						class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
  2347. -						class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
  2348. -						class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  2349. -					{
  2350. -						// job modification
  2351. -						if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
  2352. -							class_[i] = (sex ? JOB_BARD : JOB_DANCER);
  2353. -						else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
  2354. -							class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
  2355. -						else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
  2356. -							class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
  2357. -						else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
  2358. -							class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
  2359. -						else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
  2360. -							class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
  2361. -						else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
  2362. -							class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
  2363. -						else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  2364. -							class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
  2365. -					}
  2366. -
  2367. -					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]) )
  2368. -						Sql_ShowDebug(sql_handle);
  2369. -
  2370. -					if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
  2371. -						inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
  2372. -				}
  2373. -				Sql_FreeResult(sql_handle);
  2374. -
  2375. -				// disconnect player if online on char-server
  2376. -				disconnect_player(acc);
  2377. -			}
  2378. -
  2379. -			// notify all mapservers about this change
  2380. -			WBUFW(buf,0) = 0x2b0d;
  2381. -			WBUFL(buf,2) = acc;
  2382. -			WBUFB(buf,6) = sex;
  2383. -			mapif_sendall(buf, 7);
  2384. -		}
  2385. -		break;
  2386. -
  2387. -		// reply to an account_reg2 registry request
  2388. -		case 0x2729:
  2389. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2390. -				return 0;
  2391. -
  2392. -		{	//Receive account_reg2 registry, forward to map servers.
  2393. -			unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
  2394. -			memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  2395. -			WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  2396. -			mapif_sendall(buf, WBUFW(buf,2));
  2397. -			RFIFOSKIP(fd, RFIFOW(fd,2));
  2398. -		}
  2399. -		break;
  2400. -
  2401. -		// State change of account/ban notification (from login-server)
  2402. -		case 0x2731:
  2403. -			if (RFIFOREST(fd) < 11)
  2404. -				return 0;
  2405. -
  2406. -		{	// send to all map-servers to disconnect the player
  2407. -			unsigned char buf[11];
  2408. -			WBUFW(buf,0) = 0x2b14;
  2409. -			WBUFL(buf,2) = RFIFOL(fd,2);
  2410. -			WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  2411. -			WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  2412. -			mapif_sendall(buf, 11);
  2413. -		}
  2414. -			// disconnect player if online on char-server
  2415. -			disconnect_player(RFIFOL(fd,2));
  2416. -
  2417. -			RFIFOSKIP(fd,11);
  2418. -		break;
  2419. -
  2420. -		// Login server request to kick a character out. [Skotlex]
  2421. -		case 0x2734:
  2422. -			if (RFIFOREST(fd) < 6)
  2423. -				return 0;
  2424. -		{
  2425. -			int aid = RFIFOL(fd,2);
  2426. -			struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
  2427. -			RFIFOSKIP(fd,6);
  2428. -			if( character != NULL )
  2429. -			{// account is already marked as online!
  2430. -				if( character->server > -1 )
  2431. -				{	//Kick it from the map server it is on.
  2432. -					mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  2433. -					if (character->waiting_disconnect == INVALID_TIMER)
  2434. -						character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
  2435. -				}
  2436. -				else
  2437. -				{// Manual kick from char server.
  2438. -					struct char_session_data *tsd;
  2439. -					int i;
  2440. -					ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
  2441. -					if( i < fd_max )
  2442. -					{
  2443. -						WFIFOHEAD(i,3);
  2444. -						WFIFOW(i,0) = 0x81;
  2445. -						WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
  2446. -						WFIFOSET(i,3);
  2447. -						set_eof(i);
  2448. -					}
  2449. -					else // still moving to the map-server
  2450. -						set_char_offline(-1, aid);
  2451. -				}
  2452. -			}
  2453. -			idb_remove(auth_db, aid);// reject auth attempts from map-server
  2454. -		}
  2455. -		break;
  2456. -
  2457. -		// ip address update signal from login server
  2458. -		case 0x2735:
  2459. -		{
  2460. -			unsigned char buf[2];
  2461. -			uint32 new_ip = 0;
  2462. -
  2463. -			WBUFW(buf,0) = 0x2b1e;
  2464. -			mapif_sendall(buf, 2);
  2465. -
  2466. -			new_ip = host2ip(login_ip_str);
  2467. -			if (new_ip && new_ip != login_ip)
  2468. -				login_ip = new_ip; //Update login ip, too.
  2469. -
  2470. -			new_ip = host2ip(char_ip_str);
  2471. -			if (new_ip && new_ip != char_ip)
  2472. -			{	//Update ip.
  2473. -				char_ip = new_ip;
  2474. -				ShowInfo("Updating IP for [%s].\n", char_ip_str);
  2475. -				// notify login server about the change
  2476. -				WFIFOHEAD(fd,6);
  2477. -				WFIFOW(fd,0) = 0x2736;
  2478. -				WFIFOL(fd,2) = htonl(char_ip);
  2479. -				WFIFOSET(fd,6);
  2480. -			}
  2481. -
  2482. -			RFIFOSKIP(fd,2);
  2483. -		}
  2484. -		break;
  2485. -
  2486. -		default:
  2487. -			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
  2488. -			set_eof(fd);
  2489. -			return 0;
  2490. -		}
  2491. -	}
  2492. -
  2493. -	RFIFOFLUSH(fd);
  2494. -	return 0;
  2495. -}
  2496. -
  2497.  int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data);
  2498.  int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
  2499.  
  2500. @@ -2779,729 +2408,851 @@
  2501.  	mapif_server_reset(id);
  2502.  }
  2503.  
  2504. +void do_init_mapif(void)
  2505. +{
  2506. +	int i;
  2507. +	for( i = 0; i < ARRAYLENGTH(server); ++i )
  2508. +		mapif_server_init(i);
  2509. +}
  2510.  
  2511. -int parse_frommap(int fd)
  2512. +void do_final_mapif(void)
  2513.  {
  2514. +	int i;
  2515. +	for( i = 0; i < ARRAYLENGTH(server); ++i )
  2516. +		mapif_server_destroy(i);
  2517. +}
  2518. +
  2519. +// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
  2520. +// If found, returns the server's index in the 'server' array (otherwise returns -1).
  2521. +int search_mapserver(unsigned short map, uint32 ip, uint16 port)
  2522. +{
  2523.  	int i, j;
  2524. -	int id;
  2525.  
  2526. -	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  2527. -	if( id == ARRAYLENGTH(server) )
  2528. -	{// not a map server
  2529. -		ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
  2530. -		do_close(fd);
  2531. -		return 0;
  2532. +	for(i = 0; i < ARRAYLENGTH(server); i++)
  2533. +	{
  2534. +		if (server[i].fd > 0
  2535. +		&& (ip == (uint32)-1 || server[i].ip == ip)
  2536. +		&& (port == (uint16)-1 || server[i].port == port))
  2537. +		{
  2538. +			for (j = 0; server[i].map[j]; j++)
  2539. +				if (server[i].map[j] == map)
  2540. +					return i;
  2541. +		}
  2542.  	}
  2543. -	if( session[fd]->flag.eof )
  2544. -	{
  2545. -		do_close(fd);
  2546. -		server[id].fd = -1;
  2547. -		mapif_on_disconnect(id);
  2548. +
  2549. +	return -1;
  2550. +}
  2551. +
  2552. +// Initialization process (currently only initialization inter_mapif)
  2553. +static int char_mapif_init(int fd)
  2554. +{
  2555. +	return inter_mapif_init(fd);
  2556. +}
  2557. +
  2558. +//--------------------------------------------
  2559. +// Test to know if an IP come from LAN or WAN.
  2560. +//--------------------------------------------
  2561. +int lan_subnetcheck(uint32 ip)
  2562. +{
  2563. +	int i;
  2564. +	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  2565. +	if( i < subnet_count ) {
  2566. +		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));
  2567. +		return subnet[i].map_ip;
  2568. +	} else {
  2569. +		ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
  2570.  		return 0;
  2571.  	}
  2572. +}
  2573.  
  2574. -	while(RFIFOREST(fd) >= 2){
  2575. -		switch(RFIFOW(fd,0)){
  2576.  
  2577. -		case 0x2afa: // Receiving map names list from the map-server
  2578. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2579. -				return 0;
  2580. +//For use in packets that depend on an sd being present [Skotlex]
  2581. +#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
  2582.  
  2583. -			memset(server[id].map, 0, sizeof(server[id].map));
  2584. -			j = 0;
  2585. -			for(i = 4; i < RFIFOW(fd,2); i += 4) {
  2586. -				server[id].map[j] = RFIFOW(fd,i);
  2587. -				j++;
  2588. -			}
  2589. +///
  2590. +/// Map IF
  2591. +///
  2592.  
  2593. -			ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  2594. -						id, j, CONVIP(server[id].ip), server[id].port);
  2595. -			ShowStatus("Map-server %d loading complete.\n", id);
  2596. +int char_parsemap_getmapname(int fd, int id){
  2597. +	int j = 0, i = 0;
  2598. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2599. +		return 0;
  2600.  
  2601. -			// send name for wisp to player
  2602. -			WFIFOHEAD(fd, 3 + NAME_LENGTH);
  2603. -			WFIFOW(fd,0) = 0x2afb;
  2604. -			WFIFOB(fd,2) = 0;
  2605. -			memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
  2606. -			WFIFOSET(fd,3+NAME_LENGTH);
  2607. +	memset(server[id].map, 0, sizeof(server[id].map));
  2608. +	for(i = 4; i < RFIFOW(fd,2); i += 4) {
  2609. +		server[id].map[j] = RFIFOW(fd,i);
  2610. +		j++;
  2611. +	}
  2612.  
  2613. -			char_send_fame_list(fd); //Send fame list.
  2614. +	ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  2615. +				id, j, CONVIP(server[id].ip), server[id].port);
  2616. +	ShowStatus("Map-server %d loading complete.\n", id);
  2617.  
  2618. -			{
  2619. -			unsigned char buf[16384];
  2620. -			int x;
  2621. -			if (j == 0) {
  2622. -				ShowWarning("Map-server %d has NO maps.\n", id);
  2623. -			} else {
  2624. -				// Transmitting maps information to the other map-servers
  2625. -				WBUFW(buf,0) = 0x2b04;
  2626. -				WBUFW(buf,2) = j * 4 + 10;
  2627. -				WBUFL(buf,4) = htonl(server[id].ip);
  2628. -				WBUFW(buf,8) = htons(server[id].port);
  2629. -				memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
  2630. -				mapif_sendallwos(fd, buf, WBUFW(buf,2));
  2631. -			}
  2632. -			// Transmitting the maps of the other map-servers to the new map-server
  2633. -			for(x = 0; x < ARRAYLENGTH(server); x++) {
  2634. -				if (server[x].fd > 0 && x != id) {
  2635. -					WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
  2636. -					WFIFOW(fd,0) = 0x2b04;
  2637. -					WFIFOL(fd,4) = htonl(server[x].ip);
  2638. -					WFIFOW(fd,8) = htons(server[x].port);
  2639. -					j = 0;
  2640. -					for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
  2641. -						if (server[x].map[i])
  2642. -							WFIFOW(fd,10+(j++)*4) = server[x].map[i];
  2643. -					if (j > 0) {
  2644. -						WFIFOW(fd,2) = j * 4 + 10;
  2645. -						WFIFOSET(fd,WFIFOW(fd,2));
  2646. -					}
  2647. +	// send name for wisp to player
  2648. +	WFIFOHEAD(fd, 3 + NAME_LENGTH);
  2649. +	WFIFOW(fd,0) = 0x2afb;
  2650. +	WFIFOB(fd,2) = 0;
  2651. +	memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
  2652. +	WFIFOSET(fd,3+NAME_LENGTH);
  2653. +
  2654. +	char_send_fame_list(fd); //Send fame list.
  2655. +
  2656. +	{
  2657. +		unsigned char buf[16384];
  2658. +		int x;
  2659. +		if (j == 0) {
  2660. +			ShowWarning("Map-server %d has NO maps.\n", id);
  2661. +		} else {
  2662. +			// Transmitting maps information to the other map-servers
  2663. +			WBUFW(buf,0) = 0x2b04;
  2664. +			WBUFW(buf,2) = j * 4 + 10;
  2665. +			WBUFL(buf,4) = htonl(server[id].ip);
  2666. +			WBUFW(buf,8) = htons(server[id].port);
  2667. +			memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
  2668. +			mapif_sendallwos(fd, buf, WBUFW(buf,2));
  2669. +		}
  2670. +		// Transmitting the maps of the other map-servers to the new map-server
  2671. +		for(x = 0; x < ARRAYLENGTH(server); x++) {
  2672. +			if (server[x].fd > 0 && x != id) {
  2673. +				WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
  2674. +				WFIFOW(fd,0) = 0x2b04;
  2675. +				WFIFOL(fd,4) = htonl(server[x].ip);
  2676. +				WFIFOW(fd,8) = htons(server[x].port);
  2677. +				j = 0;
  2678. +				for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
  2679. +					if (server[x].map[i])
  2680. +						WFIFOW(fd,10+(j++)*4) = server[x].map[i];
  2681. +				if (j > 0) {
  2682. +					WFIFOW(fd,2) = j * 4 + 10;
  2683. +					WFIFOSET(fd,WFIFOW(fd,2));
  2684.  				}
  2685.  			}
  2686. -			}
  2687. -			RFIFOSKIP(fd,RFIFOW(fd,2));
  2688. -		break;
  2689. +		}
  2690. +	}
  2691. +	RFIFOSKIP(fd,RFIFOW(fd,2));
  2692. +	return 1;
  2693. +}
  2694.  
  2695. -		case 0x2afc: //Packet command is now used for sc_data request. [Skotlex]
  2696. -			if (RFIFOREST(fd) < 10)
  2697. -				return 0;
  2698. +int char_parsemap_askscdata(int fd, int id){
  2699. +	if (RFIFOREST(fd) < 10)
  2700. +		return 0;
  2701. +	{
  2702. +#ifdef ENABLE_SC_SAVING
  2703. +		int aid, cid;
  2704. +		aid = RFIFOL(fd,2);
  2705. +		cid = RFIFOL(fd,6);
  2706. +		if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
  2707. +			scdata_db, aid, cid) )
  2708.  		{
  2709. -#ifdef ENABLE_SC_SAVING
  2710. -			int aid, cid;
  2711. -			aid = RFIFOL(fd,2);
  2712. -			cid = RFIFOL(fd,6);
  2713. -			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
  2714. -				scdata_db, aid, cid) )
  2715. +			Sql_ShowDebug(sql_handle);
  2716. +			return 0;
  2717. +		}
  2718. +		if( Sql_NumRows(sql_handle) > 0 )
  2719. +		{
  2720. +			struct status_change_data scdata;
  2721. +			int count;
  2722. +			char* data;
  2723. +
  2724. +			WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
  2725. +			WFIFOW(fd,0) = 0x2b1d;
  2726. +			WFIFOL(fd,4) = aid;
  2727. +			WFIFOL(fd,8) = cid;
  2728. +			for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
  2729.  			{
  2730. -				Sql_ShowDebug(sql_handle);
  2731. -				break;
  2732. +				Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
  2733. +				Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
  2734. +				Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
  2735. +				Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
  2736. +				Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
  2737. +				Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
  2738. +				memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
  2739.  			}
  2740. -			if( Sql_NumRows(sql_handle) > 0 )
  2741. +			if (count >= 50)
  2742. +				ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
  2743. +			if (count > 0)
  2744.  			{
  2745. -				struct status_change_data scdata;
  2746. -				int count;
  2747. -				char* data;
  2748. +				WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
  2749. +				WFIFOW(fd,12) = count;
  2750. +				WFIFOSET(fd,WFIFOW(fd,2));
  2751.  
  2752. -				WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
  2753. -				WFIFOW(fd,0) = 0x2b1d;
  2754. -				WFIFOL(fd,4) = aid;
  2755. -				WFIFOL(fd,8) = cid;
  2756. -				for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
  2757. -				{
  2758. -					Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
  2759. -					Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
  2760. -					Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
  2761. -					Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
  2762. -					Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
  2763. -					Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
  2764. -					memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
  2765. -				}
  2766. -				if (count >= 50)
  2767. -					ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
  2768. -				if (count > 0)
  2769. -				{
  2770. -					WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
  2771. -					WFIFOW(fd,12) = count;
  2772. -					WFIFOSET(fd,WFIFOW(fd,2));
  2773. -
  2774. -					//Clear the data once loaded.
  2775. -					if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
  2776. -						Sql_ShowDebug(sql_handle);
  2777. -				}
  2778. +				//Clear the data once loaded.
  2779. +				if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
  2780. +					Sql_ShowDebug(sql_handle);
  2781.  			}
  2782. -			Sql_FreeResult(sql_handle);
  2783. +		}
  2784. +		Sql_FreeResult(sql_handle);
  2785.  #endif
  2786. -			RFIFOSKIP(fd, 10);
  2787. -		}
  2788. -		break;
  2789. +		RFIFOSKIP(fd, 10);
  2790. +	}
  2791. +	return 1;
  2792. +}
  2793.  
  2794. -		case 0x2afe: //set MAP user count
  2795. -			if (RFIFOREST(fd) < 4)
  2796. -				return 0;
  2797. -			if (RFIFOW(fd,2) != server[id].users) {
  2798. -				server[id].users = RFIFOW(fd,2);
  2799. -				ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
  2800. -			}
  2801. -			RFIFOSKIP(fd, 4);
  2802. -			break;
  2803. +int char_parsemap_getusercount(int fd, int id){
  2804. +	if (RFIFOREST(fd) < 4)
  2805. +		return 0;
  2806. +	if (RFIFOW(fd,2) != server[id].users) {
  2807. +		server[id].users = RFIFOW(fd,2);
  2808. +		ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
  2809. +	}
  2810. +	RFIFOSKIP(fd, 4);
  2811. +	return 1;
  2812. +}
  2813.  
  2814. -		case 0x2aff: //set MAP users
  2815. -			if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  2816. -				return 0;
  2817. -		{
  2818. -			//TODO: When data mismatches memory, update guild/party online/offline states.
  2819. -			int aid, cid;
  2820. -			struct online_char_data* character;
  2821. +int char_parsemap_regmapuser(int fd, int id){
  2822. +	int i;
  2823. +	if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  2824. +		return 0;
  2825. +	{
  2826. +		//TODO: When data mismatches memory, update guild/party online/offline states.
  2827. +		int aid, cid;
  2828. +		struct online_char_data* character;
  2829.  
  2830. -			server[id].users = RFIFOW(fd,4);
  2831. -			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
  2832. -			for(i = 0; i < server[id].users; i++) {
  2833. -				aid = RFIFOL(fd,6+i*8);
  2834. -				cid = RFIFOL(fd,6+i*8+4);
  2835. -				character = idb_ensure(online_char_db, aid, create_online_char_data);
  2836. -				if( character->server > -1 && character->server != id )
  2837. -				{
  2838. -					ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
  2839. -						character->account_id, character->char_id, character->server, id, aid, cid);
  2840. -					mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  2841. -				}
  2842. -				character->server = id;
  2843. -				character->char_id = cid;
  2844. +		server[id].users = RFIFOW(fd,4);
  2845. +		online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
  2846. +		for(i = 0; i < server[id].users; i++) {
  2847. +			aid = RFIFOL(fd,6+i*8);
  2848. +			cid = RFIFOL(fd,6+i*8+4);
  2849. +			character = idb_ensure(online_char_db, aid, create_online_char_data);
  2850. +			if( character->server > -1 && character->server != id )
  2851. +			{
  2852. +				ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
  2853. +					character->account_id, character->char_id, character->server, id, aid, cid);
  2854. +				mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  2855.  			}
  2856. -			//If any chars remain in -2, they will be cleaned in the cleanup timer.
  2857. -			RFIFOSKIP(fd,RFIFOW(fd,2));
  2858. +			character->server = id;
  2859. +			character->char_id = cid;
  2860.  		}
  2861. -		break;
  2862. +		//If any chars remain in -2, they will be cleaned in the cleanup timer.
  2863. +		RFIFOSKIP(fd,RFIFOW(fd,2));
  2864. +	}
  2865. +	return 1;
  2866. +}
  2867.  
  2868. -		case 0x2b01: // Receive character data from map-server for saving
  2869. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2870. -				return 0;
  2871. +int char_parsemap_reqsavechar(int fd, int id){
  2872. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2873. +			return 0;
  2874. +	{
  2875. +		int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
  2876. +		struct online_char_data* character;
  2877. +
  2878. +		if (size - 13 != sizeof(struct mmo_charstatus))
  2879.  		{
  2880. -			int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
  2881. -			struct online_char_data* character;
  2882. -
  2883. -			if (size - 13 != sizeof(struct mmo_charstatus))
  2884. -			{
  2885. -				ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
  2886. -				RFIFOSKIP(fd,size);
  2887. -				break;
  2888. -			}
  2889. -			//Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
  2890. -			if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
  2891. -				(character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
  2892. -				character->char_id == cid))
  2893. -			{
  2894. -				struct mmo_charstatus char_dat;
  2895. -				memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
  2896. -				mmo_char_tosql(cid, &char_dat);
  2897. -			} else {	//This may be valid on char-server reconnection, when re-sending characters that already logged off.
  2898. -				ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
  2899. -				set_char_online(id, cid, aid);
  2900. -			}
  2901. -
  2902. -			if (RFIFOB(fd,12))
  2903. -			{	//Flag, set character offline after saving. [Skotlex]
  2904. -				set_char_offline(cid, aid);
  2905. -				WFIFOHEAD(fd,10);
  2906. -				WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
  2907. -				WFIFOL(fd,2) = aid;
  2908. -				WFIFOL(fd,6) = cid;
  2909. -				WFIFOSET(fd,10);
  2910. -			}
  2911. +			ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
  2912.  			RFIFOSKIP(fd,size);
  2913. +			return 0;
  2914.  		}
  2915. -		break;
  2916. +		//Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
  2917. +		if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
  2918. +			(character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
  2919. +			character->char_id == cid))
  2920. +		{
  2921. +			struct mmo_charstatus char_dat;
  2922. +			memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
  2923. +			mmo_char_tosql(cid, &char_dat);
  2924. +		} else {	//This may be valid on char-server reconnection, when re-sending characters that already logged off.
  2925. +			ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
  2926. +			set_char_online(id, cid, aid);
  2927. +		}
  2928.  
  2929. -		case 0x2b02: // req char selection
  2930. -			if( RFIFOREST(fd) < 18 )
  2931. -				return 0;
  2932. -			else{
  2933. -				int account_id = RFIFOL(fd,2);
  2934. -				uint32 login_id1 = RFIFOL(fd,6);
  2935. -				uint32 login_id2 = RFIFOL(fd,10);
  2936. -				uint32 ip = RFIFOL(fd,14);
  2937. -				RFIFOSKIP(fd,18);
  2938. +		if (RFIFOB(fd,12))
  2939. +		{	//Flag, set character offline after saving. [Skotlex]
  2940. +			set_char_offline(cid, aid);
  2941. +			WFIFOHEAD(fd,10);
  2942. +			WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
  2943. +			WFIFOL(fd,2) = aid;
  2944. +			WFIFOL(fd,6) = cid;
  2945. +			WFIFOSET(fd,10);
  2946. +		}
  2947. +		RFIFOSKIP(fd,size);
  2948. +	}
  2949. +	return 1;
  2950. +}
  2951.  
  2952. -				if( runflag != CHARSERVER_ST_RUNNING ){
  2953. -					WFIFOHEAD(fd,7);
  2954. -					WFIFOW(fd,0) = 0x2b03;
  2955. -					WFIFOL(fd,2) = account_id;
  2956. -					WFIFOB(fd,6) = 0;// not ok
  2957. -					WFIFOSET(fd,7);
  2958. -				}else{
  2959. -					struct auth_node* node;
  2960. +int char_parsemap_authok(int fd, int id){
  2961. +	if( RFIFOREST(fd) < 18 )
  2962. +		return 0;
  2963. +	else{
  2964. +		int account_id = RFIFOL(fd,2);
  2965. +		uint32 login_id1 = RFIFOL(fd,6);
  2966. +		uint32 login_id2 = RFIFOL(fd,10);
  2967. +		uint32 ip = RFIFOL(fd,14);
  2968. +		RFIFOSKIP(fd,18);
  2969.  
  2970. -					// create temporary auth entry
  2971. -					CREATE(node, struct auth_node, 1);
  2972. -					node->account_id = account_id;
  2973. -					node->char_id = 0;
  2974. -					node->login_id1 = login_id1;
  2975. -					node->login_id2 = login_id2;
  2976. -					//node->sex = 0;
  2977. -					node->ip = ntohl(ip);
  2978. -					//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
  2979. -					//node->gmlevel = 0;
  2980. -					idb_put(auth_db, account_id, node);
  2981. +		if( runflag != CHARSERVER_ST_RUNNING ){
  2982. +			WFIFOHEAD(fd,7);
  2983. +			WFIFOW(fd,0) = 0x2b03;
  2984. +			WFIFOL(fd,2) = account_id;
  2985. +			WFIFOB(fd,6) = 0;// not ok
  2986. +			WFIFOSET(fd,7);
  2987. +		}else{
  2988. +			struct auth_node* node;
  2989.  
  2990. -					//Set char to "@ char select" in online db [Kevin]
  2991. -					set_char_charselect(account_id);
  2992. +			// create temporary auth entry
  2993. +			CREATE(node, struct auth_node, 1);
  2994. +			node->account_id = account_id;
  2995. +			node->char_id = 0;
  2996. +			node->login_id1 = login_id1;
  2997. +			node->login_id2 = login_id2;
  2998. +			//node->sex = 0;
  2999. +			node->ip = ntohl(ip);
  3000. +			//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
  3001. +			//node->gmlevel = 0;
  3002. +			idb_put(auth_db, account_id, node);
  3003.  
  3004. -					{
  3005. -						struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
  3006. +			//Set char to "@ char select" in online db [Kevin]
  3007. +			set_char_charselect(account_id);
  3008.  
  3009. -						if( character != NULL ){
  3010. -							character->pincode_success = true;
  3011. -						}
  3012. -					}
  3013. +			{
  3014. +				struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
  3015.  
  3016. -					WFIFOHEAD(fd,7);
  3017. -					WFIFOW(fd,0) = 0x2b03;
  3018. -					WFIFOL(fd,2) = account_id;
  3019. -					WFIFOB(fd,6) = 1;// ok
  3020. -					WFIFOSET(fd,7);
  3021. +				if( character != NULL ){
  3022. +					character->pincode_success = true;
  3023.  				}
  3024.  			}
  3025. -		break;
  3026.  
  3027. -		case 0x2b05: // request "change map server"
  3028. -			if (RFIFOREST(fd) < 39)
  3029. -				return 0;
  3030. -		{
  3031. -			int map_id, map_fd = -1;
  3032. -			struct mmo_charstatus* char_data;
  3033. -			struct mmo_charstatus char_dat;
  3034. +			WFIFOHEAD(fd,7);
  3035. +			WFIFOW(fd,0) = 0x2b03;
  3036. +			WFIFOL(fd,2) = account_id;
  3037. +			WFIFOB(fd,6) = 1;// ok
  3038. +			WFIFOSET(fd,7);
  3039. +		}
  3040. +	}
  3041. +	return 1;
  3042. +}
  3043.  
  3044. -			map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
  3045. -			if (map_id >= 0)
  3046. -				map_fd = server[map_id].fd;
  3047. -			//Char should just had been saved before this packet, so this should be safe. [Skotlex]
  3048. +int char_parsemap_reqchangemapserv(int fd, int id){
  3049. +	if (RFIFOREST(fd) < 39)
  3050. +		return 0;
  3051. +	{
  3052. +		int map_id, map_fd = -1;
  3053. +		struct mmo_charstatus* char_data;
  3054. +		struct mmo_charstatus char_dat;
  3055. +
  3056. +		map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
  3057. +		if (map_id >= 0)
  3058. +			map_fd = server[map_id].fd;
  3059. +		//Char should just had been saved before this packet, so this should be safe. [Skotlex]
  3060. +		char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  3061. +		if (char_data == NULL) {	//Really shouldn't happen.
  3062. +			mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
  3063.  			char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  3064. -			if (char_data == NULL) {	//Really shouldn't happen.
  3065. -				mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
  3066. -				char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  3067. -			}
  3068. +		}
  3069.  
  3070. -			if( runflag == CHARSERVER_ST_RUNNING &&
  3071. -				session_isActive(map_fd) &&
  3072. -				char_data )
  3073. -			{	//Send the map server the auth of this player.
  3074. -				struct online_char_data* data;
  3075. -				struct auth_node* node;
  3076. +		if( runflag == CHARSERVER_ST_RUNNING &&
  3077. +			session_isActive(map_fd) &&
  3078. +			char_data )
  3079. +		{	//Send the map server the auth of this player.
  3080. +			struct online_char_data* data;
  3081. +			struct auth_node* node;
  3082.  
  3083. -				//Update the "last map" as this is where the player must be spawned on the new map server.
  3084. -				char_data->last_point.map = RFIFOW(fd,18);
  3085. -				char_data->last_point.x = RFIFOW(fd,20);
  3086. -				char_data->last_point.y = RFIFOW(fd,22);
  3087. -				char_data->sex = RFIFOB(fd,30);
  3088. +			//Update the "last map" as this is where the player must be spawned on the new map server.
  3089. +			char_data->last_point.map = RFIFOW(fd,18);
  3090. +			char_data->last_point.x = RFIFOW(fd,20);
  3091. +			char_data->last_point.y = RFIFOW(fd,22);
  3092. +			char_data->sex = RFIFOB(fd,30);
  3093.  
  3094. -				// create temporary auth entry
  3095. -				CREATE(node, struct auth_node, 1);
  3096. -				node->account_id = RFIFOL(fd,2);
  3097. -				node->char_id = RFIFOL(fd,14);
  3098. -				node->login_id1 = RFIFOL(fd,6);
  3099. -				node->login_id2 = RFIFOL(fd,10);
  3100. -				node->sex = RFIFOB(fd,30);
  3101. -				node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
  3102. -				node->ip = ntohl(RFIFOL(fd,31));
  3103. -				node->group_id = RFIFOL(fd,35);
  3104. -				node->changing_mapservers = 1;
  3105. -				idb_put(auth_db, RFIFOL(fd,2), node);
  3106. +			// create temporary auth entry
  3107. +			CREATE(node, struct auth_node, 1);
  3108. +			node->account_id = RFIFOL(fd,2);
  3109. +			node->char_id = RFIFOL(fd,14);
  3110. +			node->login_id1 = RFIFOL(fd,6);
  3111. +			node->login_id2 = RFIFOL(fd,10);
  3112. +			node->sex = RFIFOB(fd,30);
  3113. +			node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
  3114. +			node->ip = ntohl(RFIFOL(fd,31));
  3115. +			node->group_id = RFIFOL(fd,35);
  3116. +			node->changing_mapservers = 1;
  3117. +			idb_put(auth_db, RFIFOL(fd,2), node);
  3118.  
  3119. -				data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
  3120. -				data->char_id = char_data->char_id;
  3121. -				data->server = map_id; //Update server where char is.
  3122. +			data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
  3123. +			data->char_id = char_data->char_id;
  3124. +			data->server = map_id; //Update server where char is.
  3125.  
  3126. -				//Reply with an ack.
  3127. -				WFIFOHEAD(fd,30);
  3128. -				WFIFOW(fd,0) = 0x2b06;
  3129. -				memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  3130. -				WFIFOSET(fd,30);
  3131. -			} else { //Reply with nak
  3132. -				WFIFOHEAD(fd,30);
  3133. -				WFIFOW(fd,0) = 0x2b06;
  3134. -				memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  3135. -				WFIFOL(fd,6) = 0; //Set login1 to 0.
  3136. -				WFIFOSET(fd,30);
  3137. -			}
  3138. -			RFIFOSKIP(fd,39);
  3139. +			//Reply with an ack.
  3140. +			WFIFOHEAD(fd,30);
  3141. +			WFIFOW(fd,0) = 0x2b06;
  3142. +			memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  3143. +			WFIFOSET(fd,30);
  3144. +		} else { //Reply with nak
  3145. +			WFIFOHEAD(fd,30);
  3146. +			WFIFOW(fd,0) = 0x2b06;
  3147. +			memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  3148. +			WFIFOL(fd,6) = 0; //Set login1 to 0.
  3149. +			WFIFOSET(fd,30);
  3150.  		}
  3151. -		break;
  3152. +		RFIFOSKIP(fd,39);
  3153. +	}
  3154. +	return 1;
  3155. +}
  3156.  
  3157. -		case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
  3158. -			if (RFIFOREST(fd) < 10)
  3159. -				return 0;
  3160. -			{
  3161. -				int char_id, friend_id;
  3162. -				char_id = RFIFOL(fd,2);
  3163. -				friend_id = RFIFOL(fd,6);
  3164. -				if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
  3165. -					friend_db, char_id, friend_id) ) {
  3166. -					Sql_ShowDebug(sql_handle);
  3167. -					break;
  3168. -				}
  3169. -				RFIFOSKIP(fd,10);
  3170. -			}
  3171. -		break;
  3172. +int char_parsemap_askrmfriend(int fd, int id){
  3173. +	if (RFIFOREST(fd) < 10)
  3174. +		return 0;
  3175. +	{
  3176. +		int char_id, friend_id;
  3177. +		char_id = RFIFOL(fd,2);
  3178. +		friend_id = RFIFOL(fd,6);
  3179. +		if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
  3180. +			friend_db, char_id, friend_id) ) {
  3181. +			Sql_ShowDebug(sql_handle);
  3182. +			return 0;
  3183. +		}
  3184. +		RFIFOSKIP(fd,10);
  3185. +	}
  3186. +	return 1;
  3187. +}
  3188.  
  3189. -		case 0x2b08: // char name request
  3190. -			if (RFIFOREST(fd) < 6)
  3191. -				return 0;
  3192. +int char_parsemap_reqcharname(int fd, int id){
  3193. +	if (RFIFOREST(fd) < 6)
  3194. +		return 0;
  3195.  
  3196. -			WFIFOHEAD(fd,30);
  3197. -			WFIFOW(fd,0) = 0x2b09;
  3198. -			WFIFOL(fd,2) = RFIFOL(fd,2);
  3199. -			char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
  3200. -			WFIFOSET(fd,30);
  3201. +	WFIFOHEAD(fd,30);
  3202. +	WFIFOW(fd,0) = 0x2b09;
  3203. +	WFIFOL(fd,2) = RFIFOL(fd,2);
  3204. +	char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
  3205. +	WFIFOSET(fd,30);
  3206.  
  3207. -			RFIFOSKIP(fd,6);
  3208. -		break;
  3209. +	RFIFOSKIP(fd,6);
  3210. +	return 1;
  3211. +}
  3212.  
  3213. -		case 0x2b0c: // Map server send information to change an email of an account -> login-server
  3214. -			if (RFIFOREST(fd) < 86)
  3215. -				return 0;
  3216. -			if (login_fd > 0) { // don't send request if no login-server
  3217. -				WFIFOHEAD(login_fd,86);
  3218. -				memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  3219. -				WFIFOW(login_fd,0) = 0x2722;
  3220. -				WFIFOSET(login_fd,86);
  3221. -			}
  3222. -			RFIFOSKIP(fd, 86);
  3223. -		break;
  3224. +int char_parsemap_reqnewemail(int fd, int id){
  3225. +	if (RFIFOREST(fd) < 86)
  3226. +		return 0;
  3227. +	if (login_fd > 0) { // don't send request if no login-server
  3228. +		WFIFOHEAD(login_fd,86);
  3229. +		memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  3230. +		WFIFOW(login_fd,0) = 0x2722;
  3231. +		WFIFOSET(login_fd,86);
  3232. +	}
  3233. +	RFIFOSKIP(fd, 86);
  3234. +	return 1;
  3235. +}
  3236.  
  3237. -		case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server)
  3238. -			if (RFIFOREST(fd) < 44)
  3239. -				return 0;
  3240. -		{
  3241. -			int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
  3242. -			char esc_name[NAME_LENGTH*2+1];
  3243. +int char_parsemap_fwlog_changestatus(int fd, int id){
  3244. +	if (RFIFOREST(fd) < 44)
  3245. +		return 0;
  3246. +	{
  3247. +		int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
  3248. +		char esc_name[NAME_LENGTH*2+1];
  3249.  
  3250. -			int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
  3251. -			const char* name = (char*)RFIFOP(fd,6); // name of the target character
  3252. -			int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
  3253. -			short year = RFIFOW(fd,32);
  3254. -			short month = RFIFOW(fd,34);
  3255. -			short day = RFIFOW(fd,36);
  3256. -			short hour = RFIFOW(fd,38);
  3257. -			short minute = RFIFOW(fd,40);
  3258. -			short second = RFIFOW(fd,42);
  3259. -			RFIFOSKIP(fd,44);
  3260. +		int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
  3261. +		const char* name = (char*)RFIFOP(fd,6); // name of the target character
  3262. +		int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
  3263. +		short year = RFIFOW(fd,32);
  3264. +		short month = RFIFOW(fd,34);
  3265. +		short day = RFIFOW(fd,36);
  3266. +		short hour = RFIFOW(fd,38);
  3267. +		short minute = RFIFOW(fd,40);
  3268. +		short second = RFIFOW(fd,42);
  3269. +		RFIFOSKIP(fd,44);
  3270.  
  3271. -			Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  3272. -			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
  3273. -				Sql_ShowDebug(sql_handle);
  3274. -			else
  3275. -			if( Sql_NumRows(sql_handle) == 0 )
  3276. -			{
  3277. -				result = 1; // 1-player not found
  3278. -			}
  3279. -			else
  3280. -			if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  3281. -				Sql_ShowDebug(sql_handle);
  3282. -				//FIXME: set proper result value?
  3283. -			else
  3284. -			{
  3285. -				char name[NAME_LENGTH];
  3286. -				int account_id;
  3287. -				char* data;
  3288. +		Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  3289. +		if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
  3290. +			Sql_ShowDebug(sql_handle);
  3291. +		else
  3292. +		if( Sql_NumRows(sql_handle) == 0 )
  3293. +		{
  3294. +			result = 1; // 1-player not found
  3295. +		}
  3296. +		else
  3297. +		if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  3298. +			Sql_ShowDebug(sql_handle);
  3299. +			//FIXME: set proper result value?
  3300. +		else
  3301. +		{
  3302. +			char name[NAME_LENGTH];
  3303. +			int account_id;
  3304. +			char* data;
  3305.  
  3306. -				Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
  3307. -				Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
  3308. +			Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
  3309. +			Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
  3310.  
  3311. -				if( login_fd <= 0 )
  3312. -					result = 3; // 3-login-server offline
  3313. -				//FIXME: need to move this check to login server [ultramage]
  3314. +			if( login_fd <= 0 )
  3315. +				result = 3; // 3-login-server offline
  3316. +			//FIXME: need to move this check to login server [ultramage]
  3317.  //				else
  3318.  //				if( acc != -1 && isGM(acc) < isGM(account_id) )
  3319.  //					result = 2; // 2-gm level too low
  3320. -				else
  3321. -				switch( type ) {
  3322. -				case 1: // block
  3323. -						WFIFOHEAD(login_fd,10);
  3324. -						WFIFOW(login_fd,0) = 0x2724;
  3325. -						WFIFOL(login_fd,2) = account_id;
  3326. -						WFIFOL(login_fd,6) = 5; // new account status
  3327. -						WFIFOSET(login_fd,10);
  3328. -				break;
  3329. -				case 2: // ban
  3330. -						WFIFOHEAD(login_fd,18);
  3331. -						WFIFOW(login_fd, 0) = 0x2725;
  3332. -						WFIFOL(login_fd, 2) = account_id;
  3333. -						WFIFOW(login_fd, 6) = year;
  3334. -						WFIFOW(login_fd, 8) = month;
  3335. -						WFIFOW(login_fd,10) = day;
  3336. -						WFIFOW(login_fd,12) = hour;
  3337. -						WFIFOW(login_fd,14) = minute;
  3338. -						WFIFOW(login_fd,16) = second;
  3339. -						WFIFOSET(login_fd,18);
  3340. -				break;
  3341. -				case 3: // unblock
  3342. -						WFIFOHEAD(login_fd,10);
  3343. -						WFIFOW(login_fd,0) = 0x2724;
  3344. -						WFIFOL(login_fd,2) = account_id;
  3345. -						WFIFOL(login_fd,6) = 0; // new account status
  3346. -						WFIFOSET(login_fd,10);
  3347. -				break;
  3348. -				case 4: // unban
  3349. -						WFIFOHEAD(login_fd,6);
  3350. -						WFIFOW(login_fd,0) = 0x272a;
  3351. -						WFIFOL(login_fd,2) = account_id;
  3352. -						WFIFOSET(login_fd,6);
  3353. -				break;
  3354. -				case 5: // changesex
  3355. -						WFIFOHEAD(login_fd,6);
  3356. -						WFIFOW(login_fd,0) = 0x2727;
  3357. -						WFIFOL(login_fd,2) = account_id;
  3358. -						WFIFOSET(login_fd,6);
  3359. -				break;
  3360. -				}
  3361. +			else
  3362. +			switch( type ) {
  3363. +			case 1: // block
  3364. +					WFIFOHEAD(login_fd,10);
  3365. +					WFIFOW(login_fd,0) = 0x2724;
  3366. +					WFIFOL(login_fd,2) = account_id;
  3367. +					WFIFOL(login_fd,6) = 5; // new account status
  3368. +					WFIFOSET(login_fd,10);
  3369. +			break;
  3370. +			case 2: // ban
  3371. +					WFIFOHEAD(login_fd,18);
  3372. +					WFIFOW(login_fd, 0) = 0x2725;
  3373. +					WFIFOL(login_fd, 2) = account_id;
  3374. +					WFIFOW(login_fd, 6) = year;
  3375. +					WFIFOW(login_fd, 8) = month;
  3376. +					WFIFOW(login_fd,10) = day;
  3377. +					WFIFOW(login_fd,12) = hour;
  3378. +					WFIFOW(login_fd,14) = minute;
  3379. +					WFIFOW(login_fd,16) = second;
  3380. +					WFIFOSET(login_fd,18);
  3381. +			break;
  3382. +			case 3: // unblock
  3383. +					WFIFOHEAD(login_fd,10);
  3384. +					WFIFOW(login_fd,0) = 0x2724;
  3385. +					WFIFOL(login_fd,2) = account_id;
  3386. +					WFIFOL(login_fd,6) = 0; // new account status
  3387. +					WFIFOSET(login_fd,10);
  3388. +			break;
  3389. +			case 4: // unban
  3390. +					WFIFOHEAD(login_fd,6);
  3391. +					WFIFOW(login_fd,0) = 0x272a;
  3392. +					WFIFOL(login_fd,2) = account_id;
  3393. +					WFIFOSET(login_fd,6);
  3394. +			break;
  3395. +			case 5: // changesex
  3396. +					WFIFOHEAD(login_fd,6);
  3397. +					WFIFOW(login_fd,0) = 0x2727;
  3398. +					WFIFOL(login_fd,2) = account_id;
  3399. +					WFIFOSET(login_fd,6);
  3400. +			break;
  3401.  			}
  3402. +		}
  3403.  
  3404. -			Sql_FreeResult(sql_handle);
  3405. +		Sql_FreeResult(sql_handle);
  3406.  
  3407. -			// send answer if a player ask, not if the server ask
  3408. -			if( acc != -1 && type != 5) { // Don't send answer for changesex
  3409. -				WFIFOHEAD(fd,34);
  3410. -				WFIFOW(fd, 0) = 0x2b0f;
  3411. -				WFIFOL(fd, 2) = acc;
  3412. -				safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
  3413. -				WFIFOW(fd,30) = type;
  3414. -				WFIFOW(fd,32) = result;
  3415. -				WFIFOSET(fd,34);
  3416. -			}
  3417. +		// send answer if a player ask, not if the server ask
  3418. +		if( acc != -1 && type != 5) { // Don't send answer for changesex
  3419. +			WFIFOHEAD(fd,34);
  3420. +			WFIFOW(fd, 0) = 0x2b0f;
  3421. +			WFIFOL(fd, 2) = acc;
  3422. +			safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
  3423. +			WFIFOW(fd,30) = type;
  3424. +			WFIFOW(fd,32) = result;
  3425. +			WFIFOSET(fd,34);
  3426.  		}
  3427. -		break;
  3428. +	}
  3429. +	return 1;
  3430. +}
  3431.  
  3432. -		case 0x2b10: // Update and send fame ranking list
  3433. -			if (RFIFOREST(fd) < 11)
  3434. -				return 0;
  3435. +int char_parsemap_updfamelist(int fd, int id){
  3436. +	if (RFIFOREST(fd) < 11)
  3437. +		return 0;
  3438. +	{
  3439. +		int cid = RFIFOL(fd, 2);
  3440. +		int fame = RFIFOL(fd, 6);
  3441. +		char type = RFIFOB(fd, 10);
  3442. +		int size;
  3443. +		struct fame_list* list;
  3444. +		int player_pos;
  3445. +		int fame_pos;
  3446. +
  3447. +		switch(type)
  3448.  		{
  3449. -			int cid = RFIFOL(fd, 2);
  3450. -			int fame = RFIFOL(fd, 6);
  3451. -			char type = RFIFOB(fd, 10);
  3452. -			int size;
  3453. -			struct fame_list* list;
  3454. -			int player_pos;
  3455. -			int fame_pos;
  3456. +			case 1:  size = fame_list_size_smith;   list = smith_fame_list;   break;
  3457. +			case 2:  size = fame_list_size_chemist; list = chemist_fame_list; break;
  3458. +			case 3:  size = fame_list_size_taekwon; list = taekwon_fame_list; break;
  3459. +			default: size = 0;                      list = NULL;              break;
  3460. +		}
  3461.  
  3462. -			switch(type)
  3463. -			{
  3464. -				case 1:  size = fame_list_size_smith;   list = smith_fame_list;   break;
  3465. -				case 2:  size = fame_list_size_chemist; list = chemist_fame_list; break;
  3466. -				case 3:  size = fame_list_size_taekwon; list = taekwon_fame_list; break;
  3467. -				default: size = 0;                      list = NULL;              break;
  3468. -			}
  3469. +		ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
  3470. +		ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
  3471.  
  3472. -			ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
  3473. -			ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
  3474. -
  3475. -			if( player_pos == size && fame_pos == size )
  3476. -				;// not on list and not enough fame to get on it
  3477. -			else if( fame_pos == player_pos )
  3478. -			{// same position
  3479. -				list[player_pos].fame = fame;
  3480. -				char_update_fame_list(type, player_pos, fame);
  3481. +		if( player_pos == size && fame_pos == size )
  3482. +			;// not on list and not enough fame to get on it
  3483. +		else if( fame_pos == player_pos )
  3484. +		{// same position
  3485. +			list[player_pos].fame = fame;
  3486. +			char_update_fame_list(type, player_pos, fame);
  3487. +		}
  3488. +		else
  3489. +		{// move in the list
  3490. +			if( player_pos == size )
  3491. +			{// new ranker - not in the list
  3492. +				ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
  3493. +				list[fame_pos].id = cid;
  3494. +				list[fame_pos].fame = fame;
  3495. +				char_loadName(cid, list[fame_pos].name);
  3496.  			}
  3497.  			else
  3498. -			{// move in the list
  3499. -				if( player_pos == size )
  3500. -				{// new ranker - not in the list
  3501. -					ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
  3502. -					list[fame_pos].id = cid;
  3503. -					list[fame_pos].fame = fame;
  3504. -					char_loadName(cid, list[fame_pos].name);
  3505. -				}
  3506. -				else
  3507. -				{// already in the list
  3508. -					if( fame_pos == size )
  3509. -						--fame_pos;// move to the end of the list
  3510. -					ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
  3511. -					list[fame_pos].fame = fame;
  3512. -				}
  3513. -				char_send_fame_list(-1);
  3514. +			{// already in the list
  3515. +				if( fame_pos == size )
  3516. +					--fame_pos;// move to the end of the list
  3517. +				ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
  3518. +				list[fame_pos].fame = fame;
  3519.  			}
  3520. -
  3521. -			RFIFOSKIP(fd,11);
  3522. +			char_send_fame_list(-1);
  3523.  		}
  3524. -		break;
  3525.  
  3526. -		// Divorce chars
  3527. -		case 0x2b11:
  3528. -			if( RFIFOREST(fd) < 10 )
  3529. -				return 0;
  3530. -			divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
  3531. -			RFIFOSKIP(fd,10);
  3532. -		break;
  3533. +		RFIFOSKIP(fd,11);
  3534. +	}
  3535. +	return 1;
  3536. +}
  3537.  
  3538. -		case 0x2b16: // Receive rates [Wizputer]
  3539. -			if( RFIFOREST(fd) < 14 )
  3540. -				return 0;
  3541. -		{
  3542. -			char esc_server_name[sizeof(server_name)*2+1];
  3543. +int char_parsemap_reqdivorce(int fd, int id){
  3544. +	if( RFIFOREST(fd) < 10 )
  3545. +		return 0;
  3546. +	divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
  3547. +	RFIFOSKIP(fd,10);
  3548. +	return 1;
  3549. +}
  3550. +int char_parsemap_updmapinfo(int fd, int id){
  3551. +	if( RFIFOREST(fd) < 14 )
  3552. +		return 0;
  3553. +	{
  3554. +		char esc_server_name[sizeof(server_name)*2+1];
  3555.  
  3556. -			Sql_EscapeString(sql_handle, esc_server_name, server_name);
  3557. +		Sql_EscapeString(sql_handle, esc_server_name, server_name);
  3558.  
  3559. -			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
  3560. -				ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
  3561. -				Sql_ShowDebug(sql_handle);
  3562. -			RFIFOSKIP(fd,14);
  3563. -		}
  3564. -		break;
  3565. +		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
  3566. +			ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
  3567. +			Sql_ShowDebug(sql_handle);
  3568. +		RFIFOSKIP(fd,14);
  3569. +	}
  3570. +	return 1;
  3571. +}
  3572. +int char_parsemap_setcharoffline(int fd, int id){
  3573. +	if (RFIFOREST(fd) < 6)
  3574. +		return 0;
  3575. +	set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
  3576. +	RFIFOSKIP(fd,10);
  3577. +	return 1;
  3578. +}
  3579. +int char_parsemap_setalloffline(int fd, int id){
  3580. +	set_all_offline(id);
  3581. +	RFIFOSKIP(fd,2);
  3582. +	return 1;
  3583. +}
  3584. +int char_parsemap_setcharonline(int fd, int id){
  3585. +	if (RFIFOREST(fd) < 10)
  3586. +		return 0;
  3587. +	set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
  3588. +	RFIFOSKIP(fd,10);
  3589. +	return 1;
  3590. +}
  3591. +int char_parsemap_reqfamelist(int fd, int id){
  3592. +	if (RFIFOREST(fd) < 2)
  3593. +		return 0;
  3594. +	char_read_fame_list();
  3595. +	char_send_fame_list(-1);
  3596. +	RFIFOSKIP(fd,2);
  3597. +	return 1;
  3598. +}
  3599.  
  3600. -		case 0x2b17: // Character disconnected set online 0 [Wizputer]
  3601. -			if (RFIFOREST(fd) < 6)
  3602. -				return 0;
  3603. -			set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
  3604. -			RFIFOSKIP(fd,10);
  3605. -		break;
  3606. +int char_parsemap_save_scdata(int fd, int id){
  3607. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  3608. +		return 0;
  3609. +	{
  3610. +#ifdef ENABLE_SC_SAVING
  3611. +		int count, aid, cid;
  3612.  
  3613. -		case 0x2b18: // Reset all chars to offline [Wizputer]
  3614. -			set_all_offline(id);
  3615. -			RFIFOSKIP(fd,2);
  3616. -		break;
  3617. +		aid = RFIFOL(fd, 4);
  3618. +		cid = RFIFOL(fd, 8);
  3619. +		count = RFIFOW(fd, 12);
  3620.  
  3621. -		case 0x2b19: // Character set online [Wizputer]
  3622. -			if (RFIFOREST(fd) < 10)
  3623. -				return 0;
  3624. -			set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
  3625. -			RFIFOSKIP(fd,10);
  3626. -		break;
  3627. -
  3628. -		case 0x2b1a: // Build and send fame ranking lists [DracoRPG]
  3629. -			if (RFIFOREST(fd) < 2)
  3630. -				return 0;
  3631. -			char_read_fame_list();
  3632. -			char_send_fame_list(-1);
  3633. -			RFIFOSKIP(fd,2);
  3634. -		break;
  3635. -
  3636. -		case 0x2b1c: //Request to save status change data. [Skotlex]
  3637. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  3638. -				return 0;
  3639. +		if( count > 0 )
  3640.  		{
  3641. -#ifdef ENABLE_SC_SAVING
  3642. -			int count, aid, cid;
  3643. +			struct status_change_data data;
  3644. +			StringBuf buf;
  3645. +			int i;
  3646.  
  3647. -			aid = RFIFOL(fd, 4);
  3648. -			cid = RFIFOL(fd, 8);
  3649. -			count = RFIFOW(fd, 12);
  3650. -
  3651. -			if( count > 0 )
  3652. +			StringBuf_Init(&buf);
  3653. +			StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
  3654. +			for( i = 0; i < count; ++i )
  3655.  			{
  3656. -				struct status_change_data data;
  3657. -				StringBuf buf;
  3658. -				int i;
  3659. -
  3660. -				StringBuf_Init(&buf);
  3661. -				StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
  3662. -				for( i = 0; i < count; ++i )
  3663. -				{
  3664. -					memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
  3665. -					if( i > 0 )
  3666. -						StringBuf_AppendStr(&buf, ", ");
  3667. -					StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
  3668. -						data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
  3669. -				}
  3670. -				if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
  3671. -					Sql_ShowDebug(sql_handle);
  3672. -				StringBuf_Destroy(&buf);
  3673. +				memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
  3674. +				if( i > 0 )
  3675. +					StringBuf_AppendStr(&buf, ", ");
  3676. +				StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
  3677. +					data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
  3678.  			}
  3679. +			if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
  3680. +				Sql_ShowDebug(sql_handle);
  3681. +			StringBuf_Destroy(&buf);
  3682. +		}
  3683.  #endif
  3684. -			RFIFOSKIP(fd, RFIFOW(fd, 2));
  3685. -		}
  3686. -		break;
  3687. +		RFIFOSKIP(fd, RFIFOW(fd, 2));
  3688. +	}
  3689. +	return 1;
  3690. +}
  3691.  
  3692. -		case 0x2b23: // map-server alive packet
  3693. -			WFIFOHEAD(fd,2);
  3694. -			WFIFOW(fd,0) = 0x2b24;
  3695. -			WFIFOSET(fd,2);
  3696. -			RFIFOSKIP(fd,2);
  3697. -		break;
  3698. +int char_parsemap_keepalive(int fd, int id){
  3699. +	WFIFOHEAD(fd,2);
  3700. +	WFIFOW(fd,0) = 0x2b24;
  3701. +	WFIFOSET(fd,2);
  3702. +	RFIFOSKIP(fd,2);
  3703. +	return 1;
  3704. +}
  3705.  
  3706. -		case 0x2b26: // auth request from map-server
  3707. -			if (RFIFOREST(fd) < 19)
  3708. -				return 0;
  3709. +int char_parsemap_reqauth(int fd, int id){
  3710. +	if (RFIFOREST(fd) < 19)
  3711. +		return 0;
  3712.  
  3713. -		{
  3714. -			int account_id;
  3715. -			int char_id;
  3716. -			int login_id1;
  3717. -			char sex;
  3718. -			uint32 ip;
  3719. -			struct auth_node* node;
  3720. -			struct mmo_charstatus* cd;
  3721. -			struct mmo_charstatus char_dat;
  3722. +	{
  3723. +		int account_id;
  3724. +		int char_id;
  3725. +		int login_id1;
  3726. +		char sex;
  3727. +		uint32 ip;
  3728. +		struct auth_node* node;
  3729. +		struct mmo_charstatus* cd;
  3730. +		struct mmo_charstatus char_dat;
  3731.  
  3732. -			account_id = RFIFOL(fd,2);
  3733. -			char_id    = RFIFOL(fd,6);
  3734. -			login_id1  = RFIFOL(fd,10);
  3735. -			sex        = RFIFOB(fd,14);
  3736. -			ip         = ntohl(RFIFOL(fd,15));
  3737. -			RFIFOSKIP(fd,19);
  3738. +		account_id = RFIFOL(fd,2);
  3739. +		char_id    = RFIFOL(fd,6);
  3740. +		login_id1  = RFIFOL(fd,10);
  3741. +		sex        = RFIFOB(fd,14);
  3742. +		ip         = ntohl(RFIFOL(fd,15));
  3743. +		RFIFOSKIP(fd,19);
  3744.  
  3745. -			node = (struct auth_node*)idb_get(auth_db, account_id);
  3746. +		node = (struct auth_node*)idb_get(auth_db, account_id);
  3747. +		cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  3748. +		if( cd == NULL )
  3749. +		{	//Really shouldn't happen.
  3750. +			mmo_char_fromsql(char_id, &char_dat, true);
  3751.  			cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  3752. -			if( cd == NULL )
  3753. -			{	//Really shouldn't happen.
  3754. -				mmo_char_fromsql(char_id, &char_dat, true);
  3755. -				cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  3756. -			}
  3757. -			if( runflag == CHARSERVER_ST_RUNNING &&
  3758. -				cd != NULL &&
  3759. -				node != NULL &&
  3760. -				node->account_id == account_id &&
  3761. -				node->char_id == char_id &&
  3762. -				node->login_id1 == login_id1 &&
  3763. -				node->sex == sex /*&&
  3764. -				node->ip == ip*/ )
  3765. -			{// auth ok
  3766. -				cd->sex = sex;
  3767. +		}
  3768. +		if( runflag == CHARSERVER_ST_RUNNING &&
  3769. +			cd != NULL &&
  3770. +			node != NULL &&
  3771. +			node->account_id == account_id &&
  3772. +			node->char_id == char_id &&
  3773. +			node->login_id1 == login_id1 &&
  3774. +			node->sex == sex /*&&
  3775. +			node->ip == ip*/ )
  3776. +		{// auth ok
  3777. +			cd->sex = sex;
  3778.  
  3779. -				WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
  3780. -				WFIFOW(fd,0) = 0x2afd;
  3781. -				WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
  3782. -				WFIFOL(fd,4) = account_id;
  3783. -				WFIFOL(fd,8) = node->login_id1;
  3784. -				WFIFOL(fd,12) = node->login_id2;
  3785. -				WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
  3786. -				WFIFOL(fd,20) = node->group_id;
  3787. -				WFIFOB(fd,24) = node->changing_mapservers;
  3788. -				memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
  3789. -				WFIFOSET(fd, WFIFOW(fd,2));
  3790. +			WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
  3791. +			WFIFOW(fd,0) = 0x2afd;
  3792. +			WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
  3793. +			WFIFOL(fd,4) = account_id;
  3794. +			WFIFOL(fd,8) = node->login_id1;
  3795. +			WFIFOL(fd,12) = node->login_id2;
  3796. +			WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
  3797. +			WFIFOL(fd,20) = node->group_id;
  3798. +			WFIFOB(fd,24) = node->changing_mapservers;
  3799. +			memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
  3800. +			WFIFOSET(fd, WFIFOW(fd,2));
  3801.  
  3802. -				// only use the auth once and mark user online
  3803. -				idb_remove(auth_db, account_id);
  3804. -				set_char_online(id, char_id, account_id);
  3805. -			}
  3806. -			else
  3807. -			{// auth failed
  3808. -				WFIFOHEAD(fd,19);
  3809. -				WFIFOW(fd,0) = 0x2b27;
  3810. -				WFIFOL(fd,2) = account_id;
  3811. -				WFIFOL(fd,6) = char_id;
  3812. -				WFIFOL(fd,10) = login_id1;
  3813. -				WFIFOB(fd,14) = sex;
  3814. -				WFIFOL(fd,15) = htonl(ip);
  3815. -				WFIFOSET(fd,19);
  3816. -			}
  3817. +			// only use the auth once and mark user online
  3818. +			idb_remove(auth_db, account_id);
  3819. +			set_char_online(id, char_id, account_id);
  3820.  		}
  3821. -		break;
  3822. +		else
  3823. +		{// auth failed
  3824. +			WFIFOHEAD(fd,19);
  3825. +			WFIFOW(fd,0) = 0x2b27;
  3826. +			WFIFOL(fd,2) = account_id;
  3827. +			WFIFOL(fd,6) = char_id;
  3828. +			WFIFOL(fd,10) = login_id1;
  3829. +			WFIFOB(fd,14) = sex;
  3830. +			WFIFOL(fd,15) = htonl(ip);
  3831. +			WFIFOSET(fd,19);
  3832. +		}
  3833. +	}
  3834. +	return 1;
  3835. +}
  3836.  
  3837. -		case 0x2736: // ip address update
  3838. -			if (RFIFOREST(fd) < 6) return 0;
  3839. -			server[id].ip = ntohl(RFIFOL(fd, 2));
  3840. -			ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
  3841. -			RFIFOSKIP(fd,6);
  3842. -		break;
  3843. +int char_parsemap_updmapip(int fd, int id){
  3844. +	if (RFIFOREST(fd) < 6) return 0;
  3845. +	server[id].ip = ntohl(RFIFOL(fd, 2));
  3846. +	ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
  3847. +	RFIFOSKIP(fd,6);
  3848. +	return 1;
  3849. +}
  3850.  
  3851. -		case 0x3008:
  3852. -			if( RFIFOREST(fd) < RFIFOW(fd,4) )
  3853. -				return 0;/* packet wasn't fully received yet (still fragmented) */
  3854. -			else {
  3855. -				int sfd;/* stat server fd */
  3856. -				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 */
  3857. +int char_parsemap_fw_configstats(int fd, int id){
  3858. +	if( RFIFOREST(fd) < RFIFOW(fd,4) )
  3859. +		return 0;/* packet wasn't fully received yet (still fragmented) */
  3860. +	else {
  3861. +		int sfd;/* stat server fd */
  3862. +		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 */
  3863.  
  3864. -				if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
  3865. -					RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  3866. -					break;/* connection not possible, we drop the report */
  3867. -				}
  3868. -
  3869. -				session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
  3870. -				WFIFOHEAD(sfd, RFIFOW(fd,2) );
  3871. -				memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
  3872. -				WFIFOSET(sfd, RFIFOW(fd,2) );
  3873. -				flush_fifo(sfd);
  3874. -				do_close(sfd);
  3875. -				RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  3876. +		if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
  3877. +			RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  3878. +			return 0;/* connection not possible, we drop the report */
  3879.  		}
  3880. -		break;
  3881.  
  3882. +		session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
  3883. +		WFIFOHEAD(sfd, RFIFOW(fd,2) );
  3884. +		memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
  3885. +		WFIFOSET(sfd, RFIFOW(fd,2) );
  3886. +		flush_fifo(sfd);
  3887. +		do_close(sfd);
  3888. +		RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  3889. +	}
  3890. +	return 1;
  3891. +}
  3892. +
  3893. +int parse_frommap(int fd){
  3894. +	int id; //mapserv id
  3895. +	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  3896. +	if( id == ARRAYLENGTH(server) )
  3897. +	{// not a map server
  3898. +		ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
  3899. +		do_close(fd);
  3900. +		return 0;
  3901. +	}
  3902. +	if( session[fd]->flag.eof )
  3903. +	{
  3904. +		do_close(fd);
  3905. +		server[id].fd = -1;
  3906. +		mapif_on_disconnect(id);
  3907. +		return 0;
  3908. +	}
  3909. +
  3910. +	while(RFIFOREST(fd) >= 2){
  3911. +		switch(RFIFOW(fd,0)){
  3912. +		// Receiving map names list from the map-server
  3913. +		case 0x2afa: char_parsemap_getmapname(fd,id); break;
  3914. +		//Packet command is now used for sc_data request. [Skotlex]
  3915. +		case 0x2afc: char_parsemap_askscdata(fd,id); break;
  3916. +		//MAP user count
  3917. +		case 0x2afe: char_parsemap_getusercount(fd,id); break; //get nb user
  3918. +		case 0x2aff: char_parsemap_regmapuser(fd,id); break; //register users
  3919. +		// Receive character data from map-server for saving
  3920. +		case 0x2b01: char_parsemap_reqsavechar(fd,id); break;
  3921. +		// req char selection;
  3922. +		case 0x2b02: char_parsemap_authok(fd,id); break;
  3923. +		// request "change map server"
  3924. +		case 0x2b05: char_parsemap_reqchangemapserv(fd,id); break;
  3925. +		// Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
  3926. +		case 0x2b07: char_parsemap_askrmfriend(fd,id); break;
  3927. +		// char name request
  3928. +		case 0x2b08: char_parsemap_reqcharname(fd,id); break;
  3929. +		// Map server send information to change an email of an account -> login-server
  3930. +		case 0x2b0c: char_parsemap_reqnewemail(fd,id); break;
  3931. +		// Request from map-server to change an account's status (will just be forwarded to login server)
  3932. +		case 0x2b0e: char_parsemap_fwlog_changestatus(fd,id); break;
  3933. +		// Update and send fame ranking list
  3934. +		case 0x2b10: char_parsemap_updfamelist(fd,id); break;
  3935. +		// Divorce chars
  3936. +		case 0x2b11: char_parsemap_reqdivorce(fd,id); break;
  3937. +		// Receive rates [Wizputer]
  3938. +		case 0x2b16: char_parsemap_updmapinfo(fd,id); break;
  3939. +		// Character disconnected set online 0 [Wizputer]
  3940. +		case 0x2b17: char_parsemap_setcharoffline(fd,id); break;
  3941. +		// Reset all chars to offline [Wizputer]
  3942. +		case 0x2b18: char_parsemap_setalloffline(fd,id); break;
  3943. +		// Character set online [Wizputer]
  3944. +		case 0x2b19: char_parsemap_setcharonline(fd,id); break;
  3945. +		// Build and send fame ranking lists [DracoRPG]
  3946. +		case 0x2b1a: char_parsemap_reqfamelist(fd,id); break;
  3947. +		//Request to save status change data. [Skotlex]
  3948. +		case 0x2b1c: char_parsemap_save_scdata(fd,id); break;
  3949. +		// map-server alive packet
  3950. +		case 0x2b23: char_parsemap_keepalive(fd,id); break;
  3951. +		// auth request from map-server
  3952. +		case 0x2b26: char_parsemap_reqauth(fd,id); break;
  3953. +		// ip address update
  3954. +		case 0x2736: char_parsemap_updmapip(fd,id); break;
  3955. +		// transmit emu usage for anom stats
  3956. +		case 0x3008: char_parsemap_fw_configstats(fd,id); break;
  3957.  		default:
  3958.  		{
  3959.  			// inter server - packet
  3960.  			int r = inter_parse_frommap(fd);
  3961.  			if (r == 1) break;		// processed
  3962.  			if (r == 2) return 0;	// need more packet
  3963. -
  3964.  			// no inter server packet. no char server packet -> disconnect
  3965.  			ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
  3966.  			set_eof(fd);
  3967. @@ -3513,64 +3264,10 @@
  3968.  	return 0;
  3969.  }
  3970.  
  3971. -void do_init_mapif(void)
  3972. -{
  3973. -	int i;
  3974. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  3975. -		mapif_server_init(i);
  3976. -}
  3977. +//
  3978. +// Client IF
  3979. +//
  3980.  
  3981. -void do_final_mapif(void)
  3982. -{
  3983. -	int i;
  3984. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  3985. -		mapif_server_destroy(i);
  3986. -}
  3987. -
  3988. -// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
  3989. -// If found, returns the server's index in the 'server' array (otherwise returns -1).
  3990. -int search_mapserver(unsigned short map, uint32 ip, uint16 port)
  3991. -{
  3992. -	int i, j;
  3993. -
  3994. -	for(i = 0; i < ARRAYLENGTH(server); i++)
  3995. -	{
  3996. -		if (server[i].fd > 0
  3997. -		&& (ip == (uint32)-1 || server[i].ip == ip)
  3998. -		&& (port == (uint16)-1 || server[i].port == port))
  3999. -		{
  4000. -			for (j = 0; server[i].map[j]; j++)
  4001. -				if (server[i].map[j] == map)
  4002. -					return i;
  4003. -		}
  4004. -	}
  4005. -
  4006. -	return -1;
  4007. -}
  4008. -
  4009. -// Initialization process (currently only initialization inter_mapif)
  4010. -static int char_mapif_init(int fd)
  4011. -{
  4012. -	return inter_mapif_init(fd);
  4013. -}
  4014. -
  4015. -//--------------------------------------------
  4016. -// Test to know if an IP come from LAN or WAN.
  4017. -//--------------------------------------------
  4018. -int lan_subnetcheck(uint32 ip)
  4019. -{
  4020. -	int i;
  4021. -	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  4022. -	if( i < subnet_count ) {
  4023. -		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));
  4024. -		return subnet[i].map_ip;
  4025. -	} else {
  4026. -		ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
  4027. -		return 0;
  4028. -	}
  4029. -}
  4030. -
  4031. -
  4032.  /// @param result
  4033.  /// 0 (0x718): An unknown error has occurred.
  4034.  /// 1: none/success
  4035. @@ -3588,7 +3285,6 @@
  4036.  	WFIFOSET(fd,14);
  4037.  }
  4038.  
  4039. -
  4040.  /// @param result
  4041.  /// 0 (0x718): An unknown error has occurred.
  4042.  /// 1: none/success
  4043. @@ -3606,7 +3302,6 @@
  4044.  	WFIFOSET(fd,10);
  4045.  }
  4046.  
  4047. -
  4048.  /// @param result
  4049.  /// 1 (0x718): none/success, (if char id not in deletion process): An unknown error has occurred.
  4050.  /// 2 (0x719): A database error occurred.
  4051. @@ -3620,34 +3315,37 @@
  4052.  	WFIFOSET(fd,10);
  4053.  }
  4054.  
  4055. -
  4056. -static void char_delete2_req(int fd, struct char_session_data* sd)
  4057. -{// CH: <0827>.W <char id>.L
  4058. +// CH: <0827>.W <char id>.L
  4059. +int char_parse_delete2_req(int fd, struct char_session_data* sd)
  4060. +{
  4061.  	int char_id, i;
  4062.  	char* data;
  4063.  	time_t delete_date;
  4064.  
  4065. +	FIFOSD_CHECK(6)
  4066. +
  4067.  	char_id = RFIFOL(fd,2);
  4068. +	RFIFOSKIP(fd,6);
  4069.  
  4070.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  4071.  	if( i == MAX_CHARS )
  4072.  	{// character not found
  4073.  		char_delete2_ack(fd, char_id, 3, 0);
  4074. -		return;
  4075. +		return 0;
  4076.  	}
  4077.  
  4078.  	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) )
  4079.  	{
  4080.  		Sql_ShowDebug(sql_handle);
  4081.  		char_delete2_ack(fd, char_id, 3, 0);
  4082. -		return;
  4083. +		return 0;
  4084.  	}
  4085.  
  4086.  	Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10);
  4087.  
  4088.  	if( delete_date ) {// character already queued for deletion
  4089.  		char_delete2_ack(fd, char_id, 0, 0);
  4090. -		return;
  4091. +		return 0;
  4092.  	}
  4093.  
  4094.  /*
  4095. @@ -3674,14 +3372,14 @@
  4096.  	{
  4097.  		Sql_ShowDebug(sql_handle);
  4098.  		char_delete2_ack(fd, char_id, 3, 0);
  4099. -		return;
  4100. +		return 0;
  4101.  	}
  4102.  
  4103.  	char_delete2_ack(fd, char_id, 1, delete_date);
  4104. +	return 1;
  4105.  }
  4106.  
  4107. -
  4108. -static void char_delete2_accept(int fd, struct char_session_data* sd)
  4109. +int char_parse_delete2_accept(int fd, struct char_session_data* sd)
  4110.  {// CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
  4111.  	char birthdate[8+1];
  4112.  	int char_id, i, k;
  4113. @@ -3689,6 +3387,8 @@
  4114.  	char* data;
  4115.  	time_t delete_date;
  4116.  
  4117. +	FIFOSD_CHECK(12)
  4118. +
  4119.  	char_id = RFIFOL(fd,2);
  4120.  
  4121.  	ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id);
  4122. @@ -3703,19 +3403,20 @@
  4123.  	birthdate[6] = RFIFOB(fd,10);
  4124.  	birthdate[7] = RFIFOB(fd,11);
  4125.  	birthdate[8] = 0;
  4126. +	RFIFOSKIP(fd,12);
  4127.  
  4128.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  4129.  	if( i == MAX_CHARS )
  4130.  	{// character not found
  4131.  		char_delete2_accept_ack(fd, char_id, 3);
  4132. -		return;
  4133. +		return 0;
  4134.  	}
  4135.  
  4136.  	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) )
  4137.  	{// data error
  4138.  		Sql_ShowDebug(sql_handle);
  4139.  		char_delete2_accept_ack(fd, char_id, 3);
  4140. -		return;
  4141. +		return 0;
  4142.  	}
  4143.  
  4144.  	Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10);
  4145. @@ -3724,26 +3425,26 @@
  4146.  	if( !delete_date || delete_date>time(NULL) )
  4147.  	{// not queued or delay not yet passed
  4148.  		char_delete2_accept_ack(fd, char_id, 4);
  4149. -		return;
  4150. +		return 0;
  4151.  	}
  4152.  
  4153.  	if( strcmp(sd->birthdate+2, birthdate) )  // +2 to cut off the century
  4154.  	{// birth date is wrong
  4155.  		char_delete2_accept_ack(fd, char_id, 5);
  4156. -		return;
  4157. +		return 0;
  4158.  	}
  4159.  
  4160.  	if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) )
  4161.  	{// character level config restriction
  4162.  		char_delete2_accept_ack(fd, char_id, 2);
  4163. -		return;
  4164. +		return 0;
  4165.  	}
  4166.  
  4167.  	// success
  4168.  	if( delete_char_sql(char_id) < 0 )
  4169.  	{
  4170.  		char_delete2_accept_ack(fd, char_id, 3);
  4171. -		return;
  4172. +		return 0;
  4173.  	}
  4174.  
  4175.  	// refresh character list cache
  4176. @@ -3754,20 +3455,24 @@
  4177.  	sd->found_char[MAX_CHARS-1] = -1;
  4178.  
  4179.  	char_delete2_accept_ack(fd, char_id, 1);
  4180. +	return 1;
  4181.  }
  4182.  
  4183. -
  4184. -static void char_delete2_cancel(int fd, struct char_session_data* sd)
  4185. -{// CH: <082b>.W <char id>.L
  4186. +// CH: <082b>.W <char id>.L
  4187. +int char_parse_delete2_cancel(int fd, struct char_session_data* sd)
  4188. +{
  4189.  	int char_id, i;
  4190.  
  4191. +	FIFOSD_CHECK(6)
  4192. +
  4193.  	char_id = RFIFOL(fd,2);
  4194. +	RFIFOSKIP(fd,6);
  4195.  
  4196.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  4197.  	if( i == MAX_CHARS )
  4198.  	{// character not found
  4199.  		char_delete2_cancel_ack(fd, char_id, 2);
  4200. -		return;
  4201. +		return 0;
  4202.  	}
  4203.  
  4204.  	// there is no need to check, whether or not the character was
  4205. @@ -3777,637 +3482,52 @@
  4206.  	{
  4207.  		Sql_ShowDebug(sql_handle);
  4208.  		char_delete2_cancel_ack(fd, char_id, 2);
  4209. -		return;
  4210. +		return 0;
  4211.  	}
  4212.  
  4213.  	char_delete2_cancel_ack(fd, char_id, 1);
  4214. +	return 1;
  4215.  }
  4216.  
  4217. +int char_parse_maplogin(int fd){
  4218. +	int i;
  4219.  
  4220. -int parse_char(int fd)
  4221. -{
  4222. -	int i, ch;
  4223. -	char email[40];
  4224. -	unsigned short cmd;
  4225. -	int map_fd;
  4226. -	struct char_session_data* sd;
  4227. -	uint32 ipl = session[fd]->client_addr;
  4228. -
  4229. -	sd = (struct char_session_data*)session[fd]->session_data;
  4230. -
  4231. -	// disconnect any player if no login-server.
  4232. -	if(login_fd < 0)
  4233. -		set_eof(fd);
  4234. -
  4235. -	if(session[fd]->flag.eof)
  4236. -	{
  4237. -		if( sd != NULL && sd->auth )
  4238. -		{	// already authed client
  4239. -			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
  4240. -			if( data != NULL && data->fd == fd)
  4241. -				data->fd = -1;
  4242. -			if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
  4243. -				set_char_offline(-1,sd->account_id);
  4244. -		}
  4245. -		do_close(fd);
  4246. +	if (RFIFOREST(fd) < 60)
  4247.  		return 0;
  4248. -	}
  4249. -
  4250. -	while( RFIFOREST(fd) >= 2 )
  4251. -	{
  4252. -		//For use in packets that depend on an sd being present [Skotlex]
  4253. -		#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
  4254. -
  4255. -		cmd = RFIFOW(fd,0);
  4256. -		switch( cmd )
  4257. +	else {
  4258. +		char* l_user = (char*)RFIFOP(fd,2);
  4259. +		char* l_pass = (char*)RFIFOP(fd,26);
  4260. +		l_user[23] = '\0';
  4261. +		l_pass[23] = '\0';
  4262. +		ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
  4263. +		if( runflag != CHARSERVER_ST_RUNNING ||
  4264. +			i == ARRAYLENGTH(server) ||
  4265. +			strcmp(l_user, userid) != 0 ||
  4266. +			strcmp(l_pass, passwd) != 0 )
  4267.  		{
  4268. +			WFIFOHEAD(fd,3);
  4269. +			WFIFOW(fd,0) = 0x2af9;
  4270. +			WFIFOB(fd,2) = 3;
  4271. +			WFIFOSET(fd,3);
  4272. +		} else {
  4273. +			WFIFOHEAD(fd,3);
  4274. +			WFIFOW(fd,0) = 0x2af9;
  4275. +			WFIFOB(fd,2) = 0;
  4276. +			WFIFOSET(fd,3);
  4277.  
  4278. -		// request to connect
  4279. -		// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  4280. -		case 0x65:
  4281. -			if( RFIFOREST(fd) < 17 )
  4282. -				return 0;
  4283. -		{
  4284. -			struct auth_node* node;
  4285. -
  4286. -			int account_id = RFIFOL(fd,2);
  4287. -			uint32 login_id1 = RFIFOL(fd,6);
  4288. -			uint32 login_id2 = RFIFOL(fd,10);
  4289. -			int sex = RFIFOB(fd,16);
  4290. -			RFIFOSKIP(fd,17);
  4291. -
  4292. -			ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  4293. -
  4294. -			if (sd) {
  4295. -				//Received again auth packet for already authentified account?? Discard it.
  4296. -				//TODO: Perhaps log this as a hack attempt?
  4297. -				//TODO: and perhaps send back a reply?
  4298. -				break;
  4299. -			}
  4300. -
  4301. -			CREATE(session[fd]->session_data, struct char_session_data, 1);
  4302. -			sd = (struct char_session_data*)session[fd]->session_data;
  4303. -			sd->account_id = account_id;
  4304. -			sd->login_id1 = login_id1;
  4305. -			sd->login_id2 = login_id2;
  4306. -			sd->sex = sex;
  4307. -			sd->auth = false; // not authed yet
  4308. -
  4309. -			// send back account_id
  4310. -			WFIFOHEAD(fd,4);
  4311. -			WFIFOL(fd,0) = account_id;
  4312. -			WFIFOSET(fd,4);
  4313. -
  4314. -			if( runflag != CHARSERVER_ST_RUNNING )
  4315. -			{
  4316. -				WFIFOHEAD(fd,3);
  4317. -				WFIFOW(fd,0) = 0x6c;
  4318. -				WFIFOB(fd,2) = 0;// rejected from server
  4319. -				WFIFOSET(fd,3);
  4320. -				break;
  4321. -			}
  4322. -
  4323. -			// search authentification
  4324. -			node = (struct auth_node*)idb_get(auth_db, account_id);
  4325. -			if( node != NULL &&
  4326. -			    node->account_id == account_id &&
  4327. -				node->login_id1  == login_id1 &&
  4328. -				node->login_id2  == login_id2 /*&&
  4329. -				node->ip         == ipl*/ )
  4330. -			{// authentication found (coming from map server)
  4331. -				idb_remove(auth_db, account_id);
  4332. -				char_auth_ok(fd, sd);
  4333. -			}
  4334. -			else
  4335. -			{// authentication not found (coming from login server)
  4336. -				if (login_fd > 0) { // don't send request if no login-server
  4337. -					WFIFOHEAD(login_fd,23);
  4338. -					WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  4339. -					WFIFOL(login_fd,2) = sd->account_id;
  4340. -					WFIFOL(login_fd,6) = sd->login_id1;
  4341. -					WFIFOL(login_fd,10) = sd->login_id2;
  4342. -					WFIFOB(login_fd,14) = sd->sex;
  4343. -					WFIFOL(login_fd,15) = htonl(ipl);
  4344. -					WFIFOL(login_fd,19) = fd;
  4345. -					WFIFOSET(login_fd,23);
  4346. -				} else { // if no login-server, we must refuse connection
  4347. -					WFIFOHEAD(fd,3);
  4348. -					WFIFOW(fd,0) = 0x6c;
  4349. -					WFIFOB(fd,2) = 0;
  4350. -					WFIFOSET(fd,3);
  4351. -				}
  4352. -			}
  4353. +			server[i].fd = fd;
  4354. +			server[i].ip = ntohl(RFIFOL(fd,54));
  4355. +			server[i].port = ntohs(RFIFOW(fd,58));
  4356. +			server[i].users = 0;
  4357. +			memset(server[i].map, 0, sizeof(server[i].map));
  4358. +			session[fd]->func_parse = parse_frommap;
  4359. +			session[fd]->flag.server = 1;
  4360. +			realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  4361. +			char_mapif_init(fd);
  4362.  		}
  4363. -		break;
  4364. -
  4365. -		// char select
  4366. -		case 0x66:
  4367. -			FIFOSD_CHECK(3);
  4368. -		{
  4369. -			struct mmo_charstatus char_dat;
  4370. -			struct mmo_charstatus *cd;
  4371. -			char* data;
  4372. -			int char_id;
  4373. -			uint32 subnet_map_ip;
  4374. -			struct auth_node* node;
  4375. -
  4376. -			int slot = RFIFOB(fd,2);
  4377. -			RFIFOSKIP(fd,3);
  4378. -
  4379. -			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)
  4380. -			  || SQL_SUCCESS != Sql_NextRow(sql_handle)
  4381. -			  || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
  4382. -			{	//Not found?? May be forged packet.
  4383. -				Sql_ShowDebug(sql_handle);
  4384. -				Sql_FreeResult(sql_handle);
  4385. -				WFIFOHEAD(fd,3);
  4386. -				WFIFOW(fd,0) = 0x6c;
  4387. -				WFIFOB(fd,2) = 0; // rejected from server
  4388. -				WFIFOSET(fd,3);
  4389. -				break;
  4390. -			}
  4391. -
  4392. -			char_id = atoi(data);
  4393. -			Sql_FreeResult(sql_handle);
  4394. -
  4395. -			/* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  4396. -			set_char_online(-2,char_id,sd->account_id);
  4397. -			if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  4398. -				set_char_offline(char_id, sd->account_id);
  4399. -				/* failed to load something. REJECT! */
  4400. -				WFIFOHEAD(fd,3);
  4401. -				WFIFOW(fd,0) = 0x6c;
  4402. -				WFIFOB(fd,2) = 0;
  4403. -				WFIFOSET(fd,3);
  4404. -				break;/* jump off this boat */
  4405. -			}
  4406. -
  4407. -			//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  4408. -			cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
  4409. -			cd->sex = sd->sex;
  4410. -
  4411. -			if (log_char) {
  4412. -				char esc_name[NAME_LENGTH*2+1];
  4413. -
  4414. -				Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  4415. -				if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  4416. -					charlog_db, sd->account_id, slot, esc_name) )
  4417. -					Sql_ShowDebug(sql_handle);
  4418. -			}
  4419. -			ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  4420. -
  4421. -			// searching map server
  4422. -			i = search_mapserver(cd->last_point.map, -1, -1);
  4423. -
  4424. -			// if map is not found, we check major cities
  4425. -			if (i < 0 || !cd->last_point.map) {
  4426. -				unsigned short j;
  4427. -				//First check that there's actually a map server online.
  4428. -				ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
  4429. -				if (j == ARRAYLENGTH(server)) {
  4430. -					ShowInfo("Connection Closed. No map servers available.\n");
  4431. -					WFIFOHEAD(fd,3);
  4432. -					WFIFOW(fd,0) = 0x81;
  4433. -					WFIFOB(fd,2) = 1; // 01 = Server closed
  4434. -					WFIFOSET(fd,3);
  4435. -					break;
  4436. -				}
  4437. -				if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  4438. -					cd->last_point.x = 273;
  4439. -					cd->last_point.y = 354;
  4440. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  4441. -					cd->last_point.x = 120;
  4442. -					cd->last_point.y = 100;
  4443. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  4444. -					cd->last_point.x = 160;
  4445. -					cd->last_point.y = 94;
  4446. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  4447. -					cd->last_point.x = 116;
  4448. -					cd->last_point.y = 57;
  4449. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  4450. -					cd->last_point.x = 87;
  4451. -					cd->last_point.y = 117;
  4452. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  4453. -					cd->last_point.x = 94;
  4454. -					cd->last_point.y = 103;
  4455. -				} else {
  4456. -					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));
  4457. -					WFIFOHEAD(fd,3);
  4458. -					WFIFOW(fd,0) = 0x81;
  4459. -					WFIFOB(fd,2) = 1; // 01 = Server closed
  4460. -					WFIFOSET(fd,3);
  4461. -					break;
  4462. -				}
  4463. -				ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  4464. -				cd->last_point.map = j;
  4465. -			}
  4466. -
  4467. -			//Send NEW auth packet [Kevin]
  4468. -			//FIXME: is this case even possible? [ultramage]
  4469. -			if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
  4470. -			{
  4471. -				ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  4472. -				server[i].fd = -1;
  4473. -				memset(&server[i], 0, sizeof(struct mmo_map_server));
  4474. -				//Send server closed.
  4475. -				WFIFOHEAD(fd,3);
  4476. -				WFIFOW(fd,0) = 0x81;
  4477. -				WFIFOB(fd,2) = 1; // 01 = Server closed
  4478. -				WFIFOSET(fd,3);
  4479. -				break;
  4480. -			}
  4481. -
  4482. -			//Send player to map
  4483. -			WFIFOHEAD(fd,28);
  4484. -			WFIFOW(fd,0) = 0x71;
  4485. -			WFIFOL(fd,2) = cd->char_id;
  4486. -			mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
  4487. -			subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  4488. -			WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
  4489. -			WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  4490. -			WFIFOSET(fd,28);
  4491. -
  4492. -			// create temporary auth entry
  4493. -			CREATE(node, struct auth_node, 1);
  4494. -			node->account_id = sd->account_id;
  4495. -			node->char_id = cd->char_id;
  4496. -			node->login_id1 = sd->login_id1;
  4497. -			node->login_id2 = sd->login_id2;
  4498. -			node->sex = sd->sex;
  4499. -			node->expiration_time = sd->expiration_time;
  4500. -			node->group_id = sd->group_id;
  4501. -			node->ip = ipl;
  4502. -			idb_put(auth_db, sd->account_id, node);
  4503. -
  4504. -		}
  4505. -		break;
  4506. -
  4507. -		// create new char
  4508. -#if PACKETVER >= 20120307
  4509. -		// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  4510. -		case 0x970:
  4511. -			FIFOSD_CHECK(31);
  4512. -#else
  4513. -		// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  4514. -		case 0x67:
  4515. -			FIFOSD_CHECK(37);
  4516. -#endif
  4517. -
  4518. -			if( !char_new ) //turn character creation on/off [Kevin]
  4519. -				i = -2;
  4520. -			else
  4521. -#if PACKETVER >= 20120307
  4522. -				i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
  4523. -#else
  4524. -				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));
  4525. -#endif
  4526. -
  4527. -			//'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
  4528. -			if (i < 0) {
  4529. -				WFIFOHEAD(fd,3);
  4530. -				WFIFOW(fd,0) = 0x6e;
  4531. -				/* Others I found [Ind] */
  4532. -				/* 0x02 = Symbols in Character Names are forbidden */
  4533. -				/* 0x03 = You are not elegible to open the Character Slot. */
  4534. -				switch (i) {
  4535. -					case -1: WFIFOB(fd,2) = 0x00; break;
  4536. -					case -2: WFIFOB(fd,2) = 0xFF; break;
  4537. -					case -3: WFIFOB(fd,2) = 0x01; break;
  4538. -					case -4: WFIFOB(fd,2) = 0x03; break;
  4539. -				}
  4540. -				WFIFOSET(fd,3);
  4541. -			} else {
  4542. -				int len;
  4543. -				// retrieve data
  4544. -				struct mmo_charstatus char_dat;
  4545. -				mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
  4546. -
  4547. -				// send to player
  4548. -				WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  4549. -				WFIFOW(fd,0) = 0x6d;
  4550. -				len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  4551. -				WFIFOSET(fd,len);
  4552. -
  4553. -				// add new entry to the chars list
  4554. -				ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
  4555. -				if( ch < MAX_CHARS )
  4556. -					sd->found_char[ch] = i; // the char_id of the new char
  4557. -			}
  4558. -#if PACKETVER >= 20120307
  4559. -			RFIFOSKIP(fd,31);
  4560. -#else
  4561. -			RFIFOSKIP(fd,37);
  4562. -#endif
  4563. -		break;
  4564. -
  4565. -		// delete char
  4566. -		case 0x68:
  4567. -		// 2004-04-19aSakexe+ langtype 12 char deletion packet
  4568. -		case 0x1fb:
  4569. -			if (cmd == 0x68) FIFOSD_CHECK(46);
  4570. -			if (cmd == 0x1fb) FIFOSD_CHECK(56);
  4571. -		{
  4572. -			int cid = RFIFOL(fd,2);
  4573. -
  4574. -			ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
  4575. -			memcpy(email, RFIFOP(fd,6), 40);
  4576. -			RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  4577. -
  4578. -			// Check if e-mail is correct
  4579. -			if(strcmpi(email, sd->email) && //email does not matches and
  4580. -			(
  4581. -				strcmp("[email protected]", sd->email) || //it is not default email, or
  4582. -				(strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
  4583. -			)) {	//Fail
  4584. -				WFIFOHEAD(fd,3);
  4585. -				WFIFOW(fd,0) = 0x70;
  4586. -				WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
  4587. -				WFIFOSET(fd,3);
  4588. -				break;
  4589. -			}
  4590. -
  4591. -			// check if this char exists
  4592. -			ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  4593. -			if( i == MAX_CHARS )
  4594. -			{ // Such a character does not exist in the account
  4595. -				WFIFOHEAD(fd,3);
  4596. -				WFIFOW(fd,0) = 0x70;
  4597. -				WFIFOB(fd,2) = 0;
  4598. -				WFIFOSET(fd,3);
  4599. -				break;
  4600. -			}
  4601. -
  4602. -			// remove char from list and compact it
  4603. -			for(ch = i; ch < MAX_CHARS-1; ch++)
  4604. -				sd->found_char[ch] = sd->found_char[ch+1];
  4605. -			sd->found_char[MAX_CHARS-1] = -1;
  4606. -
  4607. -			/* Delete character */
  4608. -			if(delete_char_sql(cid)<0){
  4609. -				//can't delete the char
  4610. -				//either SQL error or can't delete by some CONFIG conditions
  4611. -				//del fail
  4612. -				WFIFOHEAD(fd,3);
  4613. -				WFIFOW(fd, 0) = 0x70;
  4614. -				WFIFOB(fd, 2) = 0;
  4615. -				WFIFOSET(fd, 3);
  4616. -				break;
  4617. -			}
  4618. -			/* Char successfully deleted.*/
  4619. -			WFIFOHEAD(fd,2);
  4620. -			WFIFOW(fd,0) = 0x6f;
  4621. -			WFIFOSET(fd,2);
  4622. -		}
  4623. -		break;
  4624. -
  4625. -		// client keep-alive packet (every 12 seconds)
  4626. -		// R 0187 <account ID>.l
  4627. -		case 0x187:
  4628. -			if (RFIFOREST(fd) < 6)
  4629. -				return 0;
  4630. -			RFIFOSKIP(fd,6);
  4631. -		break;
  4632. -		// char rename request
  4633. -		// R 08fc <char ID>.l <new name>.24B
  4634. -		case 0x8fc:
  4635. -			FIFOSD_CHECK(30);
  4636. -			{
  4637. -				int i, cid =RFIFOL(fd,2);
  4638. -				char name[NAME_LENGTH];
  4639. -				char esc_name[NAME_LENGTH*2+1];
  4640. -				safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH);
  4641. -				RFIFOSKIP(fd,30);
  4642. -
  4643. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  4644. -				if( i == MAX_CHARS )
  4645. -					break;
  4646. -
  4647. -				normalize_name(name,TRIM_CHARS);
  4648. -				Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  4649. -				if( !check_char_name(name,esc_name) ) {
  4650. -					i = 1;
  4651. -					safestrncpy(sd->new_name, name, NAME_LENGTH);
  4652. -				} else
  4653. -					i = 0;
  4654. -
  4655. -				WFIFOHEAD(fd, 4);
  4656. -				WFIFOW(fd,0) = 0x28e;
  4657. -				WFIFOW(fd,2) = i;
  4658. -				WFIFOSET(fd,4);
  4659. -			}
  4660. -			break;
  4661. -
  4662. -		// char rename request
  4663. -		// R 028d <account ID>.l <char ID>.l <new name>.24B
  4664. -		case 0x28d:
  4665. -			FIFOSD_CHECK(34);
  4666. -			{
  4667. -				int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6);
  4668. -				char name[NAME_LENGTH];
  4669. - 				char esc_name[NAME_LENGTH*2+1];
  4670. -				safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
  4671. -				RFIFOSKIP(fd,34);
  4672. -
  4673. -				if( aid != sd->account_id )
  4674. -					break;
  4675. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  4676. -				if( i == MAX_CHARS )
  4677. -					break;
  4678. -
  4679. -				normalize_name(name,TRIM_CHARS);
  4680. -				Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  4681. -				if( !check_char_name(name,esc_name) )
  4682. -				{
  4683. -					i = 1;
  4684. -					safestrncpy(sd->new_name, name, NAME_LENGTH);
  4685. -				}
  4686. -				else
  4687. -					i = 0;
  4688. -
  4689. -				WFIFOHEAD(fd, 4);
  4690. -				WFIFOW(fd,0) = 0x28e;
  4691. -				WFIFOW(fd,2) = i;
  4692. -				WFIFOSET(fd,4);
  4693. -			}
  4694. -			break;
  4695. -		//Confirm change name.
  4696. -		// 0x28f <char_id>.L
  4697. -		case 0x28f:
  4698. -			// 0: Sucessfull
  4699. -			// 1: This character's name has already been changed. You cannot change a character's name more than once.
  4700. -			// 2: User information is not correct.
  4701. -			// 3: You have failed to change this character's name.
  4702. -			// 4: Another user is using this character name, so please select another one.
  4703. -			FIFOSD_CHECK(6);
  4704. -			{
  4705. -				int i;
  4706. -				int cid = RFIFOL(fd,2);
  4707. -				RFIFOSKIP(fd,6);
  4708. -
  4709. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  4710. -				if( i == MAX_CHARS )
  4711. -					break;
  4712. -				i = rename_char_sql(sd, cid);
  4713. -
  4714. -				WFIFOHEAD(fd, 4);
  4715. -				WFIFOW(fd,0) = 0x290;
  4716. -				WFIFOW(fd,2) = i;
  4717. -				WFIFOSET(fd,4);
  4718. -			}
  4719. -			break;
  4720. -
  4721. -		// captcha code request (not implemented)
  4722. -		// R 07e5 <?>.w <aid>.l
  4723. -		case 0x7e5:
  4724. -			WFIFOHEAD(fd,5);
  4725. -			WFIFOW(fd,0) = 0x7e9;
  4726. -			WFIFOW(fd,2) = 5;
  4727. -			WFIFOB(fd,4) = 1;
  4728. -			WFIFOSET(fd,5);
  4729. -			RFIFOSKIP(fd,8);
  4730. -			break;
  4731. -
  4732. -		// captcha code check (not implemented)
  4733. -		// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  4734. -		case 0x7e7:
  4735. -			WFIFOHEAD(fd,5);
  4736. -			WFIFOW(fd,0) = 0x7e9;
  4737. -			WFIFOW(fd,2) = 5;
  4738. -			WFIFOB(fd,4) = 1;
  4739. -			WFIFOSET(fd,5);
  4740. -			RFIFOSKIP(fd,32);
  4741. -		break;
  4742. -
  4743. -		// deletion timer request
  4744. -		case 0x827:
  4745. -			FIFOSD_CHECK(6);
  4746. -			char_delete2_req(fd, sd);
  4747. -			RFIFOSKIP(fd,6);
  4748. -		break;
  4749. -
  4750. -		// deletion accept request
  4751. -		case 0x829:
  4752. -			FIFOSD_CHECK(12);
  4753. -			char_delete2_accept(fd, sd);
  4754. -			RFIFOSKIP(fd,12);
  4755. -		break;
  4756. -
  4757. -		// deletion cancel request
  4758. -		case 0x82b:
  4759. -			FIFOSD_CHECK(6);
  4760. -			char_delete2_cancel(fd, sd);
  4761. -			RFIFOSKIP(fd,6);
  4762. -		break;
  4763. -
  4764. -		// login as map-server
  4765. -		case 0x2af8:
  4766. -			if (RFIFOREST(fd) < 60)
  4767. -				return 0;
  4768. -			else {
  4769. -				char* l_user = (char*)RFIFOP(fd,2);
  4770. -				char* l_pass = (char*)RFIFOP(fd,26);
  4771. -				l_user[23] = '\0';
  4772. -				l_pass[23] = '\0';
  4773. -				ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
  4774. -				if( runflag != CHARSERVER_ST_RUNNING ||
  4775. -					i == ARRAYLENGTH(server) ||
  4776. -					strcmp(l_user, userid) != 0 ||
  4777. -					strcmp(l_pass, passwd) != 0 )
  4778. -				{
  4779. -					WFIFOHEAD(fd,3);
  4780. -					WFIFOW(fd,0) = 0x2af9;
  4781. -					WFIFOB(fd,2) = 3;
  4782. -					WFIFOSET(fd,3);
  4783. -				} else {
  4784. -					WFIFOHEAD(fd,3);
  4785. -					WFIFOW(fd,0) = 0x2af9;
  4786. -					WFIFOB(fd,2) = 0;
  4787. -					WFIFOSET(fd,3);
  4788. -
  4789. -					server[i].fd = fd;
  4790. -					server[i].ip = ntohl(RFIFOL(fd,54));
  4791. -					server[i].port = ntohs(RFIFOW(fd,58));
  4792. -					server[i].users = 0;
  4793. -					memset(server[i].map, 0, sizeof(server[i].map));
  4794. -					session[fd]->func_parse = parse_frommap;
  4795. -					session[fd]->flag.server = 1;
  4796. -					realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  4797. -					char_mapif_init(fd);
  4798. -				}
  4799. -				RFIFOSKIP(fd,60);
  4800. -			}
  4801. -			return 0; // avoid processing of followup packets here
  4802. -
  4803. -		// checks the entered pin
  4804. -		case 0x8b8:
  4805. -			if( RFIFOREST(fd) < 10 )
  4806. -				return 0;
  4807. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  4808. -				pincode_check( fd, sd );
  4809. -			RFIFOSKIP(fd,10);
  4810. -		break;
  4811. -
  4812. -		// request for PIN window
  4813. -		case 0x8c5:
  4814. -			if( RFIFOREST(fd) < 6 )
  4815. -				return 0;
  4816. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  4817. -				if( strlen( sd->pincode ) <= 0 ){
  4818. -					pincode_sendstate( fd, sd, PINCODE_NEW );
  4819. -				}else{
  4820. -					pincode_sendstate( fd, sd, PINCODE_ASK );
  4821. -				}
  4822. -			}
  4823. -			RFIFOSKIP(fd,6);
  4824. -		break;
  4825. -
  4826. -		// pincode change request
  4827. -		case 0x8be:
  4828. -			if( RFIFOREST(fd) < 14 )
  4829. -				return 0;
  4830. -
  4831. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  4832. -				pincode_change( fd, sd );
  4833. -
  4834. -			RFIFOSKIP(fd,14);
  4835. -		break;
  4836. -
  4837. -		// activate PIN system and set first PIN
  4838. -		case 0x8ba:
  4839. -			if( RFIFOREST(fd) < 10 )
  4840. -				return 0;
  4841. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  4842. -				pincode_setnew( fd, sd );
  4843. -			RFIFOSKIP(fd,10);
  4844. -		break;
  4845. -
  4846. -		// character movement request
  4847. -		case 0x8d4:
  4848. -			if( RFIFOREST(fd) < 8 )
  4849. -				return 0;
  4850. -
  4851. -			moveCharSlot( fd, sd, RFIFOW(fd, 2), RFIFOW(fd, 4) );
  4852. -			mmo_char_send(fd, sd);
  4853. -			RFIFOSKIP(fd,8);
  4854. -		break;
  4855. -
  4856. -		case 0x9a1:
  4857. -			if( RFIFOREST(fd) < 2 )
  4858. -				return 0;
  4859. -			char_parse_req_charlist(fd,sd);
  4860. -			RFIFOSKIP(fd,2);
  4861. -			break;
  4862. -
  4863. -		// unknown packet received
  4864. -		default:
  4865. -			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));
  4866. -			set_eof(fd);
  4867. -			return 0;
  4868. -		}
  4869. +		RFIFOSKIP(fd,60);
  4870.  	}
  4871. -
  4872. -	RFIFOFLUSH(fd);
  4873. -	return 0;
  4874. +	return 1;
  4875.  }
  4876.  
  4877.  // Console Command Parser [Wizputer]
  4878. @@ -4563,53 +3683,84 @@
  4879.  	return 0;
  4880.  }
  4881.  
  4882. -int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
  4883. -{
  4884. -	if (login_fd > 0 && session[login_fd] != NULL)
  4885. -		return 0;
  4886. +//------------------------------------------------
  4887. +//Pincode system
  4888. +//------------------------------------------------
  4889.  
  4890. -	ShowInfo("Attempt to connect to login-server...\n");
  4891. -	login_fd = make_connection(login_ip, login_port, false,10);
  4892. -	if (login_fd == -1)
  4893. -	{	//Try again later. [Skotlex]
  4894. -		login_fd = 0;
  4895. +/* pincode_sendstate transmist the pincode state to client
  4896. + * S 08b9 <seed>.L <aid>.L <state>.W (HC_SECOND_PASSWD_LOGIN)
  4897. + * state :
  4898. + *   0 = disabled / pin is correct
  4899. + *   1 = ask for pin - client sends 0x8b8
  4900. + *   2 = create new pin - client sends 0x8ba
  4901. + *   3 = pin must be changed - client 0x8be
  4902. + *   4 = create new pin - client sends 0x8ba
  4903. + *   5 = client shows msgstr(1896)
  4904. + *   6 = client shows msgstr(1897) Unable to use your KSSN number
  4905. + *   7 = char select window shows a button - client sends 0x8c5
  4906. + *   8 = pincode was incorrect
  4907. +*/
  4908. +void pincode_sendstate( int fd, struct char_session_data* sd, enum pincode_state state ){
  4909. +	WFIFOHEAD(fd, 12);
  4910. +	WFIFOW(fd, 0) = 0x8b9;
  4911. +	WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  4912. +	WFIFOL(fd, 6) = sd->account_id;
  4913. +	WFIFOW(fd,10) = state;
  4914. +	WFIFOSET(fd,12);
  4915. +}
  4916. +
  4917. +void pincode_notifyLoginPinError( int account_id ){
  4918. +	WFIFOHEAD(login_fd,6);
  4919. +	WFIFOW(login_fd,0) = 0x2739;
  4920. +	WFIFOL(login_fd,2) = account_id;
  4921. +	WFIFOSET(login_fd,6);
  4922. +}
  4923. +
  4924. +void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
  4925. +	WFIFOHEAD(login_fd,11);
  4926. +	WFIFOW(login_fd,0) = 0x2738;
  4927. +	WFIFOL(login_fd,2) = account_id;
  4928. +	strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
  4929. +	WFIFOSET(login_fd,11);
  4930. +}
  4931. +
  4932. +int char_parse_reqpincode_window(int fd, struct char_session_data* sd){
  4933. +	if( RFIFOREST(fd) < 6 )
  4934.  		return 0;
  4935. +	if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  4936. +		if( strlen( sd->pincode ) <= 0 ){
  4937. +			pincode_sendstate( fd, sd, PINCODE_NEW );
  4938. +		}else{
  4939. +			pincode_sendstate( fd, sd, PINCODE_ASK );
  4940. +		}
  4941.  	}
  4942. -	session[login_fd]->func_parse = parse_fromlogin;
  4943. -	session[login_fd]->flag.server = 1;
  4944. -	realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  4945. -
  4946. -	WFIFOHEAD(login_fd,86);
  4947. -	WFIFOW(login_fd,0) = 0x2710;
  4948. -	memcpy(WFIFOP(login_fd,2), userid, 24);
  4949. -	memcpy(WFIFOP(login_fd,26), passwd, 24);
  4950. -	WFIFOL(login_fd,50) = 0;
  4951. -	WFIFOL(login_fd,54) = htonl(char_ip);
  4952. -	WFIFOW(login_fd,58) = htons(char_port);
  4953. -	memcpy(WFIFOP(login_fd,60), server_name, 20);
  4954. -	WFIFOW(login_fd,80) = 0;
  4955. -	WFIFOW(login_fd,82) = char_maintenance;
  4956. -	WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
  4957. -	WFIFOSET(login_fd,86);
  4958. -
  4959. +	RFIFOSKIP(fd,6);
  4960.  	return 1;
  4961.  }
  4962.  
  4963. -//------------------------------------------------
  4964. -//Pincode system
  4965. -//------------------------------------------------
  4966. -void pincode_check( int fd, struct char_session_data* sd ){
  4967. -	char pin[PINCODE_LENGTH+1];
  4968. +void pincode_decrypt( uint32 userSeed, char* pin ){
  4969. +	int i, pos;
  4970. +	char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  4971. +	char *buf;
  4972. +	uint32 multiplier = 0x3498, baseSeed = 0x881234;
  4973.  
  4974. -	memset(pin,0,PINCODE_LENGTH+1);
  4975. +	for( i = 1; i < 10; i++ ){
  4976. +		userSeed = baseSeed + userSeed * multiplier;
  4977. +		pos = userSeed % ( i + 1 );
  4978. +		if( i != pos ){
  4979. +			tab[i] ^= tab[pos];
  4980. +			tab[pos] ^= tab[i];
  4981. +			tab[i] ^= tab[pos];
  4982. +		}
  4983. +	}
  4984.  
  4985. -	strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
  4986. -
  4987. -	pincode_decrypt(sd->pincode_seed, pin );
  4988. -
  4989. -	if( pincode_compare( fd, sd, pin ) ){
  4990. -		pincode_sendstate( fd, sd, PINCODE_PASSED );
  4991. +	buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
  4992. +	memset( buf, 0, PINCODE_LENGTH + 1 );
  4993. +	for( i = 0; i < PINCODE_LENGTH; i++ ){
  4994. +		sprintf( buf + i, "%d", tab[pin[i] - '0'] );
  4995.  	}
  4996. +	strcpy( pin, buf );
  4997. +	free( buf );
  4998.  }
  4999.  
  5000.  int pincode_compare( int fd, struct char_session_data* sd, char* pin ){
  5001. @@ -4627,114 +3778,110 @@
  5002.  	}
  5003.  }
  5004.  
  5005. -void pincode_change( int fd, struct char_session_data* sd ){
  5006. +int char_parse_pincode_check( int fd, struct char_session_data* sd ){
  5007. +	char pin[PINCODE_LENGTH+1];
  5008. +
  5009. +	if( RFIFOREST(fd) < 10 )
  5010. +		return 0;
  5011. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  5012. +		return 0;
  5013. +
  5014. +	memset(pin,0,PINCODE_LENGTH+1);
  5015. +	strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
  5016. +	RFIFOSKIP(fd,10);
  5017. +
  5018. +	pincode_decrypt(sd->pincode_seed, pin );
  5019. +	if( pincode_compare( fd, sd, pin ) ){
  5020. +		pincode_sendstate( fd, sd, PINCODE_PASSED );
  5021. +	}
  5022. +	return 1;
  5023. +}
  5024. +
  5025. +int char_parse_pincode_change( int fd, struct char_session_data* sd ){
  5026.  	char oldpin[PINCODE_LENGTH+1];
  5027.  	char newpin[PINCODE_LENGTH+1];
  5028.  
  5029. +	if( RFIFOREST(fd) < 14 )
  5030. +		return 0;
  5031. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  5032. +		return 0;
  5033. +
  5034.  	memset(oldpin,0,PINCODE_LENGTH+1);
  5035.  	memset(newpin,0,PINCODE_LENGTH+1);
  5036. +	strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
  5037. +	strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
  5038. +	RFIFOSKIP(fd,14);
  5039.  
  5040. -	strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
  5041.  	pincode_decrypt(sd->pincode_seed,oldpin);
  5042. -
  5043.  	if( !pincode_compare( fd, sd, oldpin ) )
  5044. -		return;
  5045. -
  5046. -	strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
  5047. +		return 0;
  5048.  	pincode_decrypt(sd->pincode_seed,newpin);
  5049.  
  5050.  	pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  5051.  	strncpy(sd->pincode, newpin, sizeof(newpin));
  5052.  
  5053.  	pincode_sendstate( fd, sd, PINCODE_PASSED );
  5054. +	return 1;
  5055.  }
  5056.  
  5057. -void pincode_setnew( int fd, struct char_session_data* sd ){
  5058. +int char_parse_pincode_setnew( int fd, struct char_session_data* sd ){
  5059.  	char newpin[PINCODE_LENGTH+1];
  5060.  
  5061.  	memset(newpin,0,PINCODE_LENGTH+1);
  5062.  
  5063. +	if( RFIFOREST(fd) < 10 )
  5064. +		return 0;
  5065. +
  5066. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  5067. +		return 0;
  5068.  	strncpy( newpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH );
  5069. +	RFIFOSKIP(fd,10);
  5070. +
  5071.  	pincode_decrypt( sd->pincode_seed, newpin );
  5072.  
  5073.  	pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  5074.  	strncpy( sd->pincode, newpin, strlen( newpin ) );
  5075.  
  5076.  	pincode_sendstate( fd, sd, PINCODE_PASSED );
  5077. +	return 1;
  5078.  }
  5079.  
  5080. -// 0 = disabled / pin is correct
  5081. -// 1 = ask for pin - client sends 0x8b8
  5082. -// 2 = create new pin - client sends 0x8ba
  5083. -// 3 = pin must be changed - client 0x8be
  5084. -// 4 = create new pin - client sends 0x8ba
  5085. -// 5 = client shows msgstr(1896)
  5086. -// 6 = client shows msgstr(1897) Unable to use your KSSN number
  5087. -// 7 = char select window shows a button - client sends 0x8c5
  5088. -// 8 = pincode was incorrect
  5089. -void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state ){
  5090. -	WFIFOHEAD(fd, 12);
  5091. -	WFIFOW(fd, 0) = 0x8b9;
  5092. -	WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  5093. -	WFIFOL(fd, 6) = sd->account_id;
  5094. -	WFIFOW(fd,10) = state;
  5095. -	WFIFOSET(fd,12);
  5096. -}
  5097.  
  5098. -void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
  5099. -	WFIFOHEAD(login_fd,11);
  5100. -	WFIFOW(login_fd,0) = 0x2738;
  5101. -	WFIFOL(login_fd,2) = account_id;
  5102. -	strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
  5103. -	WFIFOSET(login_fd,11);
  5104. +//------------------------------------------------
  5105. +//Add On system
  5106. +//------------------------------------------------
  5107. +// reason
  5108. +// 0: success
  5109. +// 1: failed
  5110. +void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  5111. +	WFIFOHEAD(fd,8);
  5112. +	WFIFOW(fd,0) = 0x8d5;
  5113. +	WFIFOW(fd,2) = 8;
  5114. +	WFIFOW(fd,4) = reason;
  5115. +	WFIFOW(fd,6) = sd->char_moves[index];
  5116. +	WFIFOSET(fd,8);
  5117.  }
  5118.  
  5119. -void pincode_notifyLoginPinError( int account_id ){
  5120. -	WFIFOHEAD(login_fd,6);
  5121. -	WFIFOW(login_fd,0) = 0x2739;
  5122. -	WFIFOL(login_fd,2) = account_id;
  5123. -	WFIFOSET(login_fd,6);
  5124. -}
  5125. +int char_parse_moveCharSlot( int fd, struct char_session_data* sd){
  5126. +	uint16 from, to;
  5127.  
  5128. -void pincode_decrypt( uint32 userSeed, char* pin ){
  5129. -	int i, pos;
  5130. -	char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  5131. -	char *buf;
  5132. -	uint32 multiplier = 0x3498, baseSeed = 0x881234;
  5133. +	if( RFIFOREST(fd) < 8 )
  5134. +		return 0;
  5135. +	from = RFIFOW(fd,2);
  5136. +	to = RFIFOW(fd,4);
  5137. +	//Cnt = RFIFOW(fd,6); //how many time we have left to change (client.. lol we don't trust him)
  5138. +	RFIFOSKIP(fd,8);
  5139.  
  5140. -	for( i = 1; i < 10; i++ ){
  5141. -		userSeed = baseSeed + userSeed * multiplier;
  5142. -		pos = userSeed % ( i + 1 );
  5143. -		if( i != pos ){
  5144. -			tab[i] ^= tab[pos];
  5145. -			tab[pos] ^= tab[i];
  5146. -			tab[i] ^= tab[pos];
  5147. -		}
  5148. -	}
  5149. -
  5150. -	buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
  5151. -	memset( buf, 0, PINCODE_LENGTH + 1 );
  5152. -	for( i = 0; i < PINCODE_LENGTH; i++ ){
  5153. -		sprintf( buf + i, "%d", tab[pin[i] - '0'] );
  5154. -	}
  5155. -	strcpy( pin, buf );
  5156. -	free( buf );
  5157. -}
  5158. -
  5159. -//------------------------------------------------
  5160. -//Add On system
  5161. -//------------------------------------------------
  5162. -void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to ){
  5163.  	// Have we changed to often or is it disabled?
  5164.  	if( !char_move_enabled || ( !char_moves_unlimited && sd->char_moves[from] <= 0 ) ){
  5165.  		moveCharSlotReply( fd, sd, from, 1 );
  5166. -		return;
  5167. +		return 0;
  5168.  	}
  5169.  
  5170.  	// We dont even have a character on the chosen slot?
  5171.  	if( sd->found_char[from] <= 0 ){
  5172.  		moveCharSlotReply( fd, sd, from, 1 );
  5173. -		return;
  5174. +		return 0;
  5175.  	}
  5176.  
  5177.  	if( sd->found_char[to] > 0 ){
  5178. @@ -4749,17 +3896,17 @@
  5179.  				moveCharSlotReply( fd, sd, from, 1 );
  5180.  				Sql_ShowDebug(sql_handle);
  5181.  				Sql_QueryStr(sql_handle,"ROLLBACK");
  5182. -				return;
  5183. +				return 0;
  5184.  			}
  5185.  		}else{
  5186.  			// Admin doesnt allow us to
  5187.  			moveCharSlotReply( fd, sd, from, 1 );
  5188. -			return;
  5189. +			return 0;
  5190.  		}
  5191.  	}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] ) ){
  5192.  		Sql_ShowDebug(sql_handle);
  5193.  		moveCharSlotReply( fd, sd, from, 1 );
  5194. -		return;
  5195. +		return 0;
  5196.  	}
  5197.  
  5198.  	if( !char_moves_unlimited ){
  5199. @@ -4770,20 +3917,9 @@
  5200.  	// We successfully moved the char - time to notify the client
  5201.  	moveCharSlotReply( fd, sd, from, 0 );
  5202.  	mmo_char_send(fd, sd);
  5203. +	return 1;
  5204.  }
  5205.  
  5206. -// reason
  5207. -// 0: success
  5208. -// 1: failed
  5209. -void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  5210. -	WFIFOHEAD(fd,8);
  5211. -	WFIFOW(fd,0) = 0x8d5;
  5212. -	WFIFOW(fd,2) = 8;
  5213. -	WFIFOW(fd,4) = reason;
  5214. -	WFIFOW(fd,6) = sd->char_moves[index];
  5215. -	WFIFOSET(fd,8);
  5216. -}
  5217. -
  5218.  //------------------------------------------------
  5219.  //Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
  5220.  //replies/disconnect the player we tried to kick. [Skotlex]
  5221. @@ -5154,6 +4290,989 @@
  5222.  	return 0;
  5223.  }
  5224.  
  5225. +
  5226. +
  5227. +// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  5228. +int char_parse_reqtoconnect(int fd, struct char_session_data* sd,uint32 ipl){
  5229. +	if( RFIFOREST(fd) < 17 ) // request to connect
  5230. +		return 0;
  5231. +	else {
  5232. +		struct auth_node* node;
  5233. +
  5234. +		int account_id = RFIFOL(fd,2);
  5235. +		uint32 login_id1 = RFIFOL(fd,6);
  5236. +		uint32 login_id2 = RFIFOL(fd,10);
  5237. +		int sex = RFIFOB(fd,16);
  5238. +		RFIFOSKIP(fd,17);
  5239. +
  5240. +		ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  5241. +
  5242. +		if (sd) {
  5243. +			//Received again auth packet for already authentified account?? Discard it.
  5244. +			//TODO: Perhaps log this as a hack attempt?
  5245. +			//TODO: and perhaps send back a reply?
  5246. +			ShowInfo("Already registered break\n");
  5247. +			return 0;
  5248. +		}
  5249. +
  5250. +		CREATE(session[fd]->session_data, struct char_session_data, 1);
  5251. +		sd = (struct char_session_data*)session[fd]->session_data;
  5252. +		sd->account_id = account_id;
  5253. +		sd->login_id1 = login_id1;
  5254. +		sd->login_id2 = login_id2;
  5255. +		sd->sex = sex;
  5256. +		sd->auth = false; // not authed yet
  5257. +
  5258. +		// send back account_id
  5259. +		WFIFOHEAD(fd,4);
  5260. +		WFIFOL(fd,0) = account_id;
  5261. +		WFIFOSET(fd,4);
  5262. +
  5263. +		if( runflag != CHARSERVER_ST_RUNNING )
  5264. +		{
  5265. +			WFIFOHEAD(fd,3);
  5266. +			WFIFOW(fd,0) = 0x6c;
  5267. +			WFIFOB(fd,2) = 0;// rejected from server
  5268. +			WFIFOSET(fd,3);
  5269. +			return 0;
  5270. +		}
  5271. +
  5272. +		// search authentification
  5273. +		node = (struct auth_node*)idb_get(auth_db, account_id);
  5274. +		if( node != NULL &&
  5275. +		    node->account_id == account_id &&
  5276. +			node->login_id1  == login_id1 &&
  5277. +			node->login_id2  == login_id2 /*&&
  5278. +			node->ip         == ipl*/ )
  5279. +		{// authentication found (coming from map server)
  5280. +			ShowInfo("char_parse_reqtoconnect: authentication found (coming from map server)\n");
  5281. +			idb_remove(auth_db, account_id);
  5282. +			char_auth_ok(fd, sd);
  5283. +		}
  5284. +		else
  5285. +		{// authentication not found (coming from login server)
  5286. +			if (login_fd > 0) { // don't send request if no login-server
  5287. +				WFIFOHEAD(login_fd,23);
  5288. +				WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  5289. +				WFIFOL(login_fd,2) = sd->account_id;
  5290. +				WFIFOL(login_fd,6) = sd->login_id1;
  5291. +				WFIFOL(login_fd,10) = sd->login_id2;
  5292. +				WFIFOB(login_fd,14) = sd->sex;
  5293. +				WFIFOL(login_fd,15) = htonl(ipl);
  5294. +				WFIFOL(login_fd,19) = fd;
  5295. +				WFIFOSET(login_fd,23);
  5296. +			} else { // if no login-server, we must refuse connection
  5297. +				WFIFOHEAD(fd,3);
  5298. +				WFIFOW(fd,0) = 0x6c;
  5299. +				WFIFOB(fd,2) = 0;
  5300. +				WFIFOSET(fd,3);
  5301. +			}
  5302. +		}
  5303. +	}
  5304. +	return 1;
  5305. +}
  5306. +
  5307. +int char_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
  5308. +	FIFOSD_CHECK(3);
  5309. +	{
  5310. +		struct mmo_charstatus char_dat;
  5311. +		struct mmo_charstatus *cd;
  5312. +		char* data;
  5313. +		int char_id;
  5314. +		uint32 subnet_map_ip;
  5315. +		struct auth_node* node;
  5316. +		int i, map_fd;
  5317. +
  5318. +		int slot = RFIFOB(fd,2);
  5319. +		RFIFOSKIP(fd,3);
  5320. +
  5321. +		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)
  5322. +		  || SQL_SUCCESS != Sql_NextRow(sql_handle)
  5323. +		  || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
  5324. +		{	//Not found?? May be forged packet.
  5325. +			Sql_ShowDebug(sql_handle);
  5326. +			Sql_FreeResult(sql_handle);
  5327. +			WFIFOHEAD(fd,3);
  5328. +			WFIFOW(fd,0) = 0x6c;
  5329. +			WFIFOB(fd,2) = 0; // rejected from server
  5330. +			WFIFOSET(fd,3);
  5331. +			return 0;
  5332. +		}
  5333. +
  5334. +		char_id = atoi(data);
  5335. +		Sql_FreeResult(sql_handle);
  5336. +
  5337. +		/* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  5338. +		set_char_online(-2,char_id,sd->account_id);
  5339. +		if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  5340. +			set_char_offline(char_id, sd->account_id);
  5341. +			/* failed to load something. REJECT! */
  5342. +			WFIFOHEAD(fd,3);
  5343. +			WFIFOW(fd,0) = 0x6c;
  5344. +			WFIFOB(fd,2) = 0;
  5345. +			WFIFOSET(fd,3);
  5346. +			return 0;/* jump off this boat */
  5347. +		}
  5348. +
  5349. +		//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  5350. +		cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
  5351. +		cd->sex = sd->sex;
  5352. +
  5353. +		if (log_char) {
  5354. +			char esc_name[NAME_LENGTH*2+1];
  5355. +
  5356. +			Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  5357. +			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  5358. +				charlog_db, sd->account_id, slot, esc_name) )
  5359. +				Sql_ShowDebug(sql_handle);
  5360. +		}
  5361. +		ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  5362. +
  5363. +		// searching map server
  5364. +		i = search_mapserver(cd->last_point.map, -1, -1);
  5365. +
  5366. +		// if map is not found, we check major cities
  5367. +		if (i < 0 || !cd->last_point.map) {
  5368. +			unsigned short j;
  5369. +			//First check that there's actually a map server online.
  5370. +			ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
  5371. +			if (j == ARRAYLENGTH(server)) {
  5372. +				ShowInfo("Connection Closed. No map servers available.\n");
  5373. +				WFIFOHEAD(fd,3);
  5374. +				WFIFOW(fd,0) = 0x81;
  5375. +				WFIFOB(fd,2) = 1; // 01 = Server closed
  5376. +				WFIFOSET(fd,3);
  5377. +				return 0;
  5378. +			}
  5379. +			if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  5380. +				cd->last_point.x = 273;
  5381. +				cd->last_point.y = 354;
  5382. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  5383. +				cd->last_point.x = 120;
  5384. +				cd->last_point.y = 100;
  5385. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  5386. +				cd->last_point.x = 160;
  5387. +				cd->last_point.y = 94;
  5388. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  5389. +				cd->last_point.x = 116;
  5390. +				cd->last_point.y = 57;
  5391. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  5392. +				cd->last_point.x = 87;
  5393. +				cd->last_point.y = 117;
  5394. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  5395. +				cd->last_point.x = 94;
  5396. +				cd->last_point.y = 103;
  5397. +			} else {
  5398. +				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));
  5399. +				WFIFOHEAD(fd,3);
  5400. +				WFIFOW(fd,0) = 0x81;
  5401. +				WFIFOB(fd,2) = 1; // 01 = Server closed
  5402. +				WFIFOSET(fd,3);
  5403. +				return 0;
  5404. +			}
  5405. +			ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  5406. +			cd->last_point.map = j;
  5407. +		}
  5408. +
  5409. +		//Send NEW auth packet [Kevin]
  5410. +		//FIXME: is this case even possible? [ultramage]
  5411. +		if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
  5412. +		{
  5413. +			ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  5414. +			server[i].fd = -1;
  5415. +			memset(&server[i], 0, sizeof(struct mmo_map_server));
  5416. +			//Send server closed.
  5417. +			WFIFOHEAD(fd,3);
  5418. +			WFIFOW(fd,0) = 0x81;
  5419. +			WFIFOB(fd,2) = 1; // 01 = Server closed
  5420. +			WFIFOSET(fd,3);
  5421. +			return 0;
  5422. +		}
  5423. +
  5424. +		//Send player to map
  5425. +		WFIFOHEAD(fd,28);
  5426. +		WFIFOW(fd,0) = 0x71;
  5427. +		WFIFOL(fd,2) = cd->char_id;
  5428. +		mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
  5429. +		subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  5430. +		WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
  5431. +		WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  5432. +		WFIFOSET(fd,28);
  5433. +
  5434. +		// create temporary auth entry
  5435. +		CREATE(node, struct auth_node, 1);
  5436. +		node->account_id = sd->account_id;
  5437. +		node->char_id = cd->char_id;
  5438. +		node->login_id1 = sd->login_id1;
  5439. +		node->login_id2 = sd->login_id2;
  5440. +		node->sex = sd->sex;
  5441. +		node->expiration_time = sd->expiration_time;
  5442. +		node->group_id = sd->group_id;
  5443. +		node->ip = ipl;
  5444. +		ShowInfo("Putting node into auth_db, node=%d, aid=%d, version=%d\n",
  5445. +			node,sd->account_id,sd->version);
  5446. +		idb_put(auth_db, sd->account_id, node);
  5447. +
  5448. +	}
  5449. +	return 1;
  5450. +}
  5451. +
  5452. +// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  5453. +// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  5454. +int char_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
  5455. +	int i=0, ch;
  5456. +
  5457. +	if (cmd == 0x970) FIFOSD_CHECK(31) //>=20120307
  5458. +	else if (cmd == 0x67) FIFOSD_CHECK(37)
  5459. +	else return 0;
  5460. +
  5461. +	if( !char_new ) //turn character creation on/off [Kevin]
  5462. +		i = -2;
  5463. +	else {
  5464. +		if (cmd == 0x970){
  5465. +			i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
  5466. +			RFIFOSKIP(fd,31);
  5467. +		}
  5468. +		else if(cmd == 0x67){
  5469. +#if PACKETVER < 20120307
  5470. +			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));
  5471. +			RFIFOSKIP(fd,37);
  5472. +#endif
  5473. +		}
  5474. +	}
  5475. +
  5476. +	//'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
  5477. +	if (i < 0) {
  5478. +		WFIFOHEAD(fd,3);
  5479. +		WFIFOW(fd,0) = 0x6e;
  5480. +		/* Others I found [Ind] */
  5481. +		/* 0x02 = Symbols in Character Names are forbidden */
  5482. +		/* 0x03 = You are not elegible to open the Character Slot. */
  5483. +		switch (i) {
  5484. +			case -1: WFIFOB(fd,2) = 0x00; break;
  5485. +			case -2: WFIFOB(fd,2) = 0xFF; break;
  5486. +			case -3: WFIFOB(fd,2) = 0x01; break;
  5487. +			case -4: WFIFOB(fd,2) = 0x03; break;
  5488. +		}
  5489. +		WFIFOSET(fd,3);
  5490. +	} else {
  5491. +		int len;
  5492. +		// retrieve data
  5493. +		struct mmo_charstatus char_dat;
  5494. +		mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
  5495. +
  5496. +		// send to player
  5497. +		WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  5498. +		WFIFOW(fd,0) = 0x6d;
  5499. +		len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  5500. +		WFIFOSET(fd,len);
  5501. +
  5502. +		// add new entry to the chars list
  5503. +		ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
  5504. +		if( ch < MAX_CHARS )
  5505. +			sd->found_char[ch] = i; // the char_id of the new char
  5506. +	}
  5507. +	return 1;
  5508. +}
  5509. +
  5510. +int char_parse_delchar(int fd,struct char_session_data* sd, int cmd){
  5511. +	char email[40];
  5512. +	int i, ch;
  5513. +
  5514. +	if (cmd == 0x68) FIFOSD_CHECK(46)
  5515. +	else if (cmd == 0x1fb) FIFOSD_CHECK(56)
  5516. +	else return 0;
  5517. +
  5518. +	{
  5519. +		int cid = RFIFOL(fd,2);
  5520. +
  5521. +		ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
  5522. +		memcpy(email, RFIFOP(fd,6), 40);
  5523. +		RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  5524. +
  5525. +		// Check if e-mail is correct
  5526. +		if(strcmpi(email, sd->email) && //email does not matches and
  5527. +		(
  5528. +			strcmp("[email protected]", sd->email) || //it is not default email, or
  5529. +			(strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
  5530. +		)) {	//Fail
  5531. +			WFIFOHEAD(fd,3);
  5532. +			WFIFOW(fd,0) = 0x70;
  5533. +			WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
  5534. +			WFIFOSET(fd,3);
  5535. +			return 0;
  5536. +		}
  5537. +
  5538. +		// check if this char exists
  5539. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  5540. +		if( i == MAX_CHARS )
  5541. +		{ // Such a character does not exist in the account
  5542. +			WFIFOHEAD(fd,3);
  5543. +			WFIFOW(fd,0) = 0x70;
  5544. +			WFIFOB(fd,2) = 0;
  5545. +			WFIFOSET(fd,3);
  5546. +			return 0;
  5547. +		}
  5548. +
  5549. +		// remove char from list and compact it
  5550. +		for(ch = i; ch < MAX_CHARS-1; ch++)
  5551. +			sd->found_char[ch] = sd->found_char[ch+1];
  5552. +		sd->found_char[MAX_CHARS-1] = -1;
  5553. +
  5554. +		/* Delete character */
  5555. +		if(delete_char_sql(cid)<0){
  5556. +			//can't delete the char
  5557. +			//either SQL error or can't delete by some CONFIG conditions
  5558. +			//del fail
  5559. +			WFIFOHEAD(fd,3);
  5560. +			WFIFOW(fd, 0) = 0x70;
  5561. +			WFIFOB(fd, 2) = 0;
  5562. +			WFIFOSET(fd, 3);
  5563. +			return 0;
  5564. +		}
  5565. +		/* Char successfully deleted.*/
  5566. +		WFIFOHEAD(fd,2);
  5567. +		WFIFOW(fd,0) = 0x6f;
  5568. +		WFIFOSET(fd,2);
  5569. +	}
  5570. +	return 1;
  5571. +}
  5572. +
  5573. +// R 0187 <account ID>.l
  5574. +int char_parse_keepalive(int fd){
  5575. +	if (RFIFOREST(fd) < 6)
  5576. +		return 0;
  5577. +	//int aid = RFIFOL(fd,2);
  5578. +	RFIFOSKIP(fd,6);
  5579. +	return 1;
  5580. +}
  5581. +
  5582. +// R 08fc <char ID>.l <new name>.24B
  5583. +// R 028d <account ID>.l <char ID>.l <new name>.24B
  5584. +int char_parse_reqrename(int fd, struct char_session_data* sd, int cmd){
  5585. +	if(cmd == 0x8fc) FIFOSD_CHECK(30)
  5586. +	if(cmd == 0x28d) FIFOSD_CHECK(34)
  5587. +	else return 0;
  5588. +
  5589. +	{
  5590. +		int i, cid=0;
  5591. +		char name[NAME_LENGTH];
  5592. +		char esc_name[NAME_LENGTH*2+1];
  5593. +		safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
  5594. +
  5595. +		if(cmd == 0x8fc){
  5596. +			cid =RFIFOL(fd,2);
  5597. +			RFIFOSKIP(fd,30);
  5598. +		}
  5599. +		else if(cmd == 0x28d) {
  5600. +			int aid = RFIFOL(fd,2);
  5601. +			cid =RFIFOL(fd,6);
  5602. +			if( aid != sd->account_id )
  5603. +				return 0;
  5604. +			RFIFOSKIP(fd,34);
  5605. +		}
  5606. +
  5607. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  5608. +		if( i == MAX_CHARS )
  5609. +			return 0;
  5610. +
  5611. +		normalize_name(name,TRIM_CHARS);
  5612. +		Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  5613. +		if( !check_char_name(name,esc_name) )
  5614. +		{
  5615. +			i = 1;
  5616. +			safestrncpy(sd->new_name, name, NAME_LENGTH);
  5617. +		}
  5618. +		else
  5619. +			i = 0;
  5620. +
  5621. +		WFIFOHEAD(fd, 4);
  5622. +		WFIFOW(fd,0) = 0x28e;
  5623. +		WFIFOW(fd,2) = i;
  5624. +		WFIFOSET(fd,4);
  5625. +	}
  5626. +	return 1;
  5627. +}
  5628. +
  5629. +// 0x28f <char_id>.L
  5630. +int char_parse_ackrename(int fd, struct char_session_data* sd){
  5631. +	// 0: Sucessfull
  5632. +	// 1: This character's name has already been changed. You cannot change a character's name more than once.
  5633. +	// 2: User information is not correct.
  5634. +	// 3: You have failed to change this character's name.
  5635. +	// 4: Another user is using this character name, so please select another one.
  5636. +	FIFOSD_CHECK(6)
  5637. +
  5638. +	{
  5639. +		int i;
  5640. +		int cid = RFIFOL(fd,2);
  5641. +		RFIFOSKIP(fd,6);
  5642. +
  5643. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  5644. +		if( i == MAX_CHARS )
  5645. +			return 0;
  5646. +		i = rename_char_sql(sd, cid);
  5647. +
  5648. +		WFIFOHEAD(fd, 4);
  5649. +		WFIFOW(fd,0) = 0x290;
  5650. +		WFIFOW(fd,2) = i;
  5651. +		WFIFOSET(fd,4);
  5652. +	}
  5653. +	return 1;
  5654. +}
  5655. +
  5656. +// R 07e5 <?>.w <aid>.l
  5657. +int char_parse_reqcaptcha(int fd){
  5658. +	WFIFOHEAD(fd,5);
  5659. +	WFIFOW(fd,0) = 0x7e9;
  5660. +	WFIFOW(fd,2) = 5;
  5661. +	WFIFOB(fd,4) = 1;
  5662. +	WFIFOSET(fd,5);
  5663. +	RFIFOSKIP(fd,8);
  5664. +	return 1;
  5665. +}
  5666. +
  5667. +// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  5668. +int char_parse_chkcaptcha(int fd){
  5669. +	WFIFOHEAD(fd,5);
  5670. +	WFIFOW(fd,0) = 0x7e9;
  5671. +	WFIFOW(fd,2) = 5;
  5672. +	WFIFOB(fd,4) = 1;
  5673. +	WFIFOSET(fd,5);
  5674. +	RFIFOSKIP(fd,32);
  5675. +	return 1;
  5676. +}
  5677. +
  5678. +
  5679. +int parse_char(int fd)
  5680. +{
  5681. +	unsigned short cmd;
  5682. +	struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
  5683. +	uint32 ipl = session[fd]->client_addr;
  5684. +
  5685. +	// disconnect any player if no login-server.
  5686. +	if(login_fd < 0)
  5687. +		set_eof(fd);
  5688. +
  5689. +	if(session[fd]->flag.eof)
  5690. +	{
  5691. +		if( sd != NULL && sd->auth )
  5692. +		{	// already authed client
  5693. +			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
  5694. +			if( data != NULL && data->fd == fd)
  5695. +				data->fd = -1;
  5696. +			if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
  5697. +				set_char_offline(-1,sd->account_id);
  5698. +		}
  5699. +		do_close(fd);
  5700. +		return 0;
  5701. +	}
  5702. +
  5703. +	while( RFIFOREST(fd) >= 2 )
  5704. +	{
  5705. +		cmd = RFIFOW(fd,0);
  5706. +		switch( cmd )
  5707. +		{
  5708. +
  5709. +		case 0x65: char_parse_reqtoconnect(fd,sd,ipl); break;
  5710. +		// char select
  5711. +		case 0x66: char_parse_charselect(fd,sd,ipl); break;
  5712. +		// createnewchar
  5713. +		case 0x970: char_parse_createnewchar(fd,sd,cmd); break;
  5714. +		case 0x67: char_parse_createnewchar(fd,sd,cmd); break;
  5715. +		// delete char
  5716. +		case 0x68: char_parse_delchar(fd,sd,cmd); break; //
  5717. +		case 0x1fb: char_parse_delchar(fd,sd,cmd); break; // 2004-04-19aSakexe+ langtype 12 char deletion packet
  5718. +		// client keep-alive packet (every 12 seconds)
  5719. +		case 0x187: char_parse_keepalive(fd); break;
  5720. +		// char rename
  5721. +		case 0x8fc: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  5722. +		case 0x28d: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  5723. +		case 0x28f: char_parse_ackrename(fd,sd); break; //Confirm change name.
  5724. +		// captcha
  5725. +		case 0x7e5: char_parse_reqcaptcha(fd); break; // captcha code request (not implemented)
  5726. +		case 0x7e7: char_parse_chkcaptcha(fd); break; // captcha code check (not implemented)
  5727. +		// deletion timer request
  5728. +		case 0x827: char_parse_delete2_req(fd, sd); break;
  5729. +		// deletion accept request
  5730. +		case 0x829: char_parse_delete2_accept(fd, sd); break;
  5731. +		// deletion cancel request
  5732. +		case 0x82b: char_parse_delete2_cancel(fd, sd); break;
  5733. +		// login as map-server
  5734. +		case 0x2af8: char_parse_maplogin(fd); return 0; // avoid processing of followup packets here
  5735. +		//pincode
  5736. +		case 0x8b8: char_parse_pincode_check( fd, sd ); break; // checks the entered pin
  5737. +		case 0x8c5: char_parse_reqpincode_window(fd,sd); break; // request for PIN window
  5738. +		case 0x8be: char_parse_pincode_change( fd, sd ); break; // pincode change request
  5739. +		case 0x8ba: char_parse_pincode_setnew( fd, sd ); break; // activate PIN system and set first PIN
  5740. +		// character movement request
  5741. +		case 0x8d4: char_parse_moveCharSlot(fd,sd); break;
  5742. +		case 0x9a1: char_parse_req_charlist(fd,sd); break;
  5743. +		// unknown packet received
  5744. +		default:
  5745. +			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));
  5746. +			set_eof(fd);
  5747. +			return 0;
  5748. +		}
  5749. +	}
  5750. +
  5751. +	RFIFOFLUSH(fd);
  5752. +	return 0;
  5753. +}
  5754. +
  5755. +///
  5756. +/// Login IF
  5757. +///
  5758. +
  5759. +int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
  5760. +{
  5761. +	if (login_fd > 0 && session[login_fd] != NULL)
  5762. +		return 0;
  5763. +
  5764. +	ShowInfo("Attempt to connect to login-server...\n");
  5765. +	login_fd = make_connection(login_ip, login_port, false,10);
  5766. +	if (login_fd == -1)
  5767. +	{	//Try again later. [Skotlex]
  5768. +		login_fd = 0;
  5769. +		return 0;
  5770. +	}
  5771. +	session[login_fd]->func_parse = parse_fromlogin;
  5772. +	session[login_fd]->flag.server = 1;
  5773. +	realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  5774. +
  5775. +	WFIFOHEAD(login_fd,86);
  5776. +	WFIFOW(login_fd,0) = 0x2710;
  5777. +	memcpy(WFIFOP(login_fd,2), userid, 24);
  5778. +	memcpy(WFIFOP(login_fd,26), passwd, 24);
  5779. +	WFIFOL(login_fd,50) = 0;
  5780. +	WFIFOL(login_fd,54) = htonl(char_ip);
  5781. +	WFIFOW(login_fd,58) = htons(char_port);
  5782. +	memcpy(WFIFOP(login_fd,60), server_name, 20);
  5783. +	WFIFOW(login_fd,80) = 0;
  5784. +	WFIFOW(login_fd,82) = char_maintenance;
  5785. +	WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
  5786. +	WFIFOSET(login_fd,86);
  5787. +
  5788. +	return 1;
  5789. +}
  5790. +
  5791. +int char_parselog_ackconnect(int fd, struct char_session_data* sd){
  5792. +	if (RFIFOREST(fd) < 3)
  5793. +		return 0;
  5794. +
  5795. +	if (RFIFOB(fd,2)) {
  5796. +		//printf("connect login server error : %d\n", RFIFOB(fd,2));
  5797. +		ShowError("Can not connect to login-server.\n");
  5798. +		ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  5799. +		ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
  5800. +		ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
  5801. +		set_eof(fd);
  5802. +		return 0;
  5803. +	} else {
  5804. +		ShowStatus("Connected to login-server (connection #%d).\n", fd);
  5805. +		loginif_on_ready();
  5806. +	}
  5807. +	RFIFOSKIP(fd,3);
  5808. +	return 1;
  5809. +}
  5810. +
  5811. +int char_parselog_ackaccreq(int fd, struct char_session_data* sd){
  5812. +	if (RFIFOREST(fd) < 25)
  5813. +		return 0;
  5814. +	{
  5815. +		int account_id = RFIFOL(fd,2);
  5816. +		uint32 login_id1 = RFIFOL(fd,6);
  5817. +		uint32 login_id2 = RFIFOL(fd,10);
  5818. +		uint8 sex = RFIFOB(fd,14);
  5819. +		uint8 result = RFIFOB(fd,15);
  5820. +		int request_id = RFIFOL(fd,16);
  5821. +		uint32 version = RFIFOL(fd,20);
  5822. +		uint8 clienttype = RFIFOB(fd,24);
  5823. +		RFIFOSKIP(fd,25);
  5824. +
  5825. +		if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
  5826. +			!sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
  5827. +		{
  5828. +			int client_fd = request_id;
  5829. +			sd->version = version;
  5830. +			sd->clienttype = clienttype;
  5831. +			switch( result )
  5832. +			{
  5833. +			case 0:// ok
  5834. +				char_auth_ok(client_fd, sd);
  5835. +				break;
  5836. +			case 1:// auth failed
  5837. +				WFIFOHEAD(client_fd,3);
  5838. +				WFIFOW(client_fd,0) = 0x6c;
  5839. +				WFIFOB(client_fd,2) = 0;// rejected from server
  5840. +				WFIFOSET(client_fd,3);
  5841. +				break;
  5842. +			}
  5843. +		}
  5844. +	}
  5845. +	return 1;
  5846. +}
  5847. +
  5848. +int char_parselog_reqaccdata(int fd, struct char_session_data* sd){
  5849. +	int i;
  5850. +	if (RFIFOREST(fd) < 73)
  5851. +		return 0;
  5852. +
  5853. +	// find the authenticated session with this account id
  5854. +	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) );
  5855. +	if( i < fd_max )
  5856. +	{
  5857. +		int server_id;
  5858. +		memcpy(sd->email, RFIFOP(fd,6), 40);
  5859. +		sd->expiration_time = (time_t)RFIFOL(fd,46);
  5860. +		sd->group_id = RFIFOB(fd,50);
  5861. +		sd->char_slots = RFIFOB(fd,51);
  5862. +		if( sd->char_slots > MAX_CHARS ) {
  5863. +			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);
  5864. +			sd->char_slots = MAX_CHARS;/* cap to maximum */
  5865. +		} else if ( !sd->char_slots )/* no value aka 0 in sql */
  5866. +			sd->char_slots = MAX_CHARS;/* cap to maximum */
  5867. +		safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
  5868. +		safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
  5869. +		sd->pincode_change = (time_t)RFIFOL(fd,68);
  5870. +		sd->version = RFIFOB(fd,72);
  5871. +		ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
  5872. +		// continued from char_auth_ok...
  5873. +		if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
  5874. +			(max_connect_user == 0 && sd->group_id != gm_allow_group) ||
  5875. +			( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
  5876. +			// refuse connection (over populated)
  5877. +			WFIFOHEAD(i,3);
  5878. +			WFIFOW(i,0) = 0x6c;
  5879. +			WFIFOW(i,2) = 0;
  5880. +			WFIFOSET(i,3);
  5881. +		} else {
  5882. +			// send characters to player
  5883. +			mmo_char_send(i, sd);
  5884. +#if PACKETVER >=  20110309
  5885. +			if( pincode_enabled ){
  5886. +				// PIN code system enabled
  5887. +				if( strlen( sd->pincode ) <= 0 ){
  5888. +					// No PIN code has been set yet
  5889. +					if( pincode_force ){
  5890. +						pincode_sendstate( i, sd, PINCODE_NEW );
  5891. +					}else{
  5892. +						pincode_sendstate( i, sd, PINCODE_PASSED );
  5893. +					}
  5894. +				}else{
  5895. +					if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
  5896. +						struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
  5897. +
  5898. +						if( node != NULL && node->pincode_success ){
  5899. +							// User has already passed the check
  5900. +							pincode_sendstate( i, sd, PINCODE_PASSED );
  5901. +						}else{
  5902. +							// Ask user for his PIN code
  5903. +							pincode_sendstate( i, sd, PINCODE_ASK );
  5904. +						}
  5905. +					}else{
  5906. +						// User hasnt changed his PIN code too long
  5907. +						pincode_sendstate( i, sd, PINCODE_EXPIRED );
  5908. +					}
  5909. +				}
  5910. +			}else{
  5911. +				// PIN code system disabled
  5912. +				pincode_sendstate( i, sd, PINCODE_OK );
  5913. +			}
  5914. +#endif
  5915. +		}
  5916. +	}
  5917. +	RFIFOSKIP(fd,73);
  5918. +	return 1;
  5919. +}
  5920. +
  5921. +int char_parselog_keepalive(int fd, struct char_session_data* sd){
  5922. +	if (RFIFOREST(fd) < 2)
  5923. +		return 0;
  5924. +	RFIFOSKIP(fd,2);
  5925. +	session[fd]->flag.ping = 0;
  5926. +	return 1;
  5927. +}
  5928. +
  5929. +int char_parselog_ackchangesex(int fd, struct char_session_data* sd){
  5930. +	if (RFIFOREST(fd) < 7)
  5931. +		return 0;
  5932. +	{
  5933. +		unsigned char buf[7];
  5934. +		int i;
  5935. +
  5936. +		int acc = RFIFOL(fd,2);
  5937. +		int sex = RFIFOB(fd,6);
  5938. +		RFIFOSKIP(fd,7);
  5939. +
  5940. +		if( acc > 0 )
  5941. +		{// TODO: Is this even possible?
  5942. +			int char_id[MAX_CHARS];
  5943. +			int class_[MAX_CHARS];
  5944. +			int guild_id[MAX_CHARS];
  5945. +			int num;
  5946. +			char* data;
  5947. +
  5948. +			struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
  5949. +			if( node != NULL )
  5950. +				node->sex = sex;
  5951. +
  5952. +			// get characters
  5953. +			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
  5954. +				Sql_ShowDebug(sql_handle);
  5955. +			for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
  5956. +			{
  5957. +				Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
  5958. +				Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
  5959. +				Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
  5960. +			}
  5961. +			num = i;
  5962. +			for( i = 0; i < num; ++i )
  5963. +			{
  5964. +				if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
  5965. +					class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
  5966. +					class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
  5967. +					class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
  5968. +					class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
  5969. +					class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
  5970. +					class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  5971. +				{
  5972. +					// job modification
  5973. +					if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
  5974. +						class_[i] = (sex ? JOB_BARD : JOB_DANCER);
  5975. +					else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
  5976. +						class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
  5977. +					else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
  5978. +						class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
  5979. +					else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
  5980. +						class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
  5981. +					else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
  5982. +						class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
  5983. +					else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
  5984. +						class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
  5985. +					else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  5986. +						class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
  5987. +				}
  5988. +
  5989. +				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]) )
  5990. +					Sql_ShowDebug(sql_handle);
  5991. +
  5992. +				if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
  5993. +					inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
  5994. +			}
  5995. +			Sql_FreeResult(sql_handle);
  5996. +
  5997. +			// disconnect player if online on char-server
  5998. +			disconnect_player(acc);
  5999. +		}
  6000. +
  6001. +		// notify all mapservers about this change
  6002. +		WBUFW(buf,0) = 0x2b0d;
  6003. +		WBUFL(buf,2) = acc;
  6004. +		WBUFB(buf,6) = sex;
  6005. +		mapif_sendall(buf, 7);
  6006. +	}
  6007. +	return 1;
  6008. +}
  6009. +
  6010. +int char_parselog_ackacc2req(int fd, struct char_session_data* sd){
  6011. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  6012. +		return 0;
  6013. +
  6014. +	{	//Receive account_reg2 registry, forward to map servers.
  6015. +		unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
  6016. +		memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  6017. +		WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  6018. +		mapif_sendall(buf, WBUFW(buf,2));
  6019. +		RFIFOSKIP(fd, RFIFOW(fd,2));
  6020. +	}
  6021. +	return 1;
  6022. +}
  6023. +
  6024. +int char_parselog_accbannotification(int fd, struct char_session_data* sd){
  6025. +	if (RFIFOREST(fd) < 11)
  6026. +		return 0;
  6027. +
  6028. +	{	// send to all map-servers to disconnect the player
  6029. +		unsigned char buf[11];
  6030. +		WBUFW(buf,0) = 0x2b14;
  6031. +		WBUFL(buf,2) = RFIFOL(fd,2);
  6032. +		WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  6033. +		WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  6034. +		mapif_sendall(buf, 11);
  6035. +	}
  6036. +	// disconnect player if online on char-server
  6037. +	disconnect_player(RFIFOL(fd,2));
  6038. +	RFIFOSKIP(fd,11);
  6039. +	return 1;
  6040. +}
  6041. +
  6042. +int char_parselog_askkick(int fd, struct char_session_data* sd){
  6043. +	if (RFIFOREST(fd) < 6)
  6044. +		return 0;
  6045. +	{
  6046. +		int aid = RFIFOL(fd,2);
  6047. +		struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
  6048. +		RFIFOSKIP(fd,6);
  6049. +		if( character != NULL )
  6050. +		{// account is already marked as online!
  6051. +			if( character->server > -1 )
  6052. +			{	//Kick it from the map server it is on.
  6053. +				mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  6054. +				if (character->waiting_disconnect == INVALID_TIMER)
  6055. +					character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
  6056. +			}
  6057. +			else
  6058. +			{// Manual kick from char server.
  6059. +				struct char_session_data *tsd;
  6060. +				int i;
  6061. +				ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
  6062. +				if( i < fd_max )
  6063. +				{
  6064. +					WFIFOHEAD(i,3);
  6065. +					WFIFOW(i,0) = 0x81;
  6066. +					WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
  6067. +					WFIFOSET(i,3);
  6068. +					set_eof(i);
  6069. +				}
  6070. +				else // still moving to the map-server
  6071. +					set_char_offline(-1, aid);
  6072. +			}
  6073. +		}
  6074. +		idb_remove(auth_db, aid);// reject auth attempts from map-server
  6075. +	}
  6076. +	return 1;
  6077. +}
  6078. +
  6079. +int char_parselog_updip(int fd, struct char_session_data* sd){
  6080. +	if (RFIFOREST(fd) < 2)
  6081. +		return 0;
  6082. +	{
  6083. +		unsigned char buf[2];
  6084. +		uint32 new_ip = 0;
  6085. +
  6086. +		WBUFW(buf,0) = 0x2b1e;
  6087. +		mapif_sendall(buf, 2);
  6088. +
  6089. +		new_ip = host2ip(login_ip_str);
  6090. +		if (new_ip && new_ip != login_ip)
  6091. +			login_ip = new_ip; //Update login ip, too.
  6092. +
  6093. +		new_ip = host2ip(char_ip_str);
  6094. +		if (new_ip && new_ip != char_ip)
  6095. +		{	//Update ip.
  6096. +			char_ip = new_ip;
  6097. +			ShowInfo("Updating IP for [%s].\n", char_ip_str);
  6098. +			// notify login server about the change
  6099. +			WFIFOHEAD(fd,6);
  6100. +			WFIFOW(fd,0) = 0x2736;
  6101. +			WFIFOL(fd,2) = htonl(char_ip);
  6102. +			WFIFOSET(fd,6);
  6103. +		}
  6104. +
  6105. +		RFIFOSKIP(fd,2);
  6106. +	}
  6107. +	return 1;
  6108. +}
  6109. +
  6110. +int parse_fromlogin(int fd) {
  6111. +	struct char_session_data* sd = NULL;
  6112. +
  6113. +	// only process data from the login-server
  6114. +	if( fd != login_fd ) {
  6115. +		ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
  6116. +		do_close(fd);
  6117. +		return 0;
  6118. +	}
  6119. +
  6120. +	if( session[fd]->flag.eof ) {
  6121. +		do_close(fd);
  6122. +		login_fd = -1;
  6123. +		loginif_on_disconnect();
  6124. +		return 0;
  6125. +	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
  6126. +		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
  6127. +			set_eof(fd);
  6128. +			return 0;
  6129. +		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
  6130. +			WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
  6131. +			WFIFOW(fd,0) = 0x2719;
  6132. +			WFIFOSET(fd,2);
  6133. +
  6134. +			session[fd]->flag.ping = 2;
  6135. +		}
  6136. +	}
  6137. +
  6138. +	sd = (struct char_session_data*)session[fd]->session_data;
  6139. +
  6140. +	while(RFIFOREST(fd) >= 2) {
  6141. +		uint16 command = RFIFOW(fd,0);
  6142. +
  6143. +		switch( command )
  6144. +		{
  6145. +		// acknowledgement of connect-to-loginserver request
  6146. +		case 0x2711: char_parselog_ackconnect(fd,sd); break;
  6147. +		// acknowledgement of account authentication request
  6148. +		case 0x2713: char_parselog_ackaccreq(fd, sd); break;
  6149. +		// account data
  6150. +		case 0x2717: char_parselog_reqaccdata(fd, sd); break;
  6151. +		// login-server alive packet
  6152. +		case 0x2718: char_parselog_keepalive(fd, sd); break;
  6153. +		// changesex reply
  6154. +		case 0x2723: char_parselog_ackchangesex(fd, sd); break;
  6155. +		// reply to an account_reg2 registry request
  6156. +		case 0x2729: char_parselog_ackacc2req(fd, sd); break;
  6157. +		// State change of account/ban notification (from login-server)
  6158. +		case 0x2731: char_parselog_accbannotification(fd, sd); break;
  6159. +		// Login server request to kick a character out. [Skotlex]
  6160. +		case 0x2734: char_parselog_askkick(fd,sd); break;
  6161. +		// ip address update signal from login server
  6162. +		case 0x2735: char_parselog_updip(fd,sd); break;
  6163. +		default:
  6164. +			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
  6165. +			set_eof(fd);
  6166. +			return 0;
  6167. +		}
  6168. +	}
  6169. +
  6170. +	RFIFOFLUSH(fd);
  6171. +	return 0;
  6172. +}
  6173. +
  6174. +
  6175. +
  6176. +
  6177. +/*======================================================
  6178. + * Login-Server help option info
  6179. + *------------------------------------------------------*/
  6180. +void display_helpscreen(bool do_exit)
  6181. +{
  6182. +	ShowInfo("Usage: %s [options]\n", SERVER_NAME);
  6183. +	ShowInfo("\n");
  6184. +	ShowInfo("Options:\n");
  6185. +	ShowInfo("  -?, -h [--help]\t\tDisplays this help screen.\n");
  6186. +	ShowInfo("  -v [--version]\t\tDisplays the server's version.\n");
  6187. +	ShowInfo("  --run-once\t\t\tCloses server after loading (testing).\n");
  6188. +	ShowInfo("  --char-config <file>\t\tAlternative char-server configuration.\n");
  6189. +	ShowInfo("  --lan-config <file>\t\tAlternative lag configuration.\n");
  6190. +	ShowInfo("  --inter-config <file>\t\tAlternative inter-server configuration.\n");
  6191. +	ShowInfo("  --msg-config <file>\t\tAlternative message configuration.\n");
  6192. +	if( do_exit )
  6193. +		exit(EXIT_SUCCESS);
  6194. +}
  6195. +
  6196. +int char_msg_config_read(char *cfgName){
  6197. +	return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
  6198. +}
  6199. +const char* char_msg_txt(int msg_number){
  6200. +	return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
  6201. +}
  6202. +void char_do_final_msg(void){
  6203. +	_do_final_msg(CHAR_MAX_MSG,msg_table);
  6204. +}
  6205. +
  6206. +
  6207. +
  6208.  void do_final(void)
  6209.  {
  6210.  	ShowStatus("Terminating...\n");
  6211. @@ -5188,6 +5307,12 @@
  6212.  	ShowStatus("Finished.\n");
  6213.  }
  6214.  
  6215. +
  6216. +void set_server_type(void)
  6217. +{
  6218. +	SERVER_TYPE = ATHENA_SERVER_CHAR;
  6219. +}
  6220. +
  6221.  //------------------------------
  6222.  // Function called when the server
  6223.  // has received a crash signal.
  6224. @@ -5196,12 +5321,6 @@
  6225.  {
  6226.  }
  6227.  
  6228. -void set_server_type(void)
  6229. -{
  6230. -	SERVER_TYPE = ATHENA_SERVER_CHAR;
  6231. -}
  6232. -
  6233. -
  6234.  /// Called when a terminate signal is received.
  6235.  void do_shutdown(void)
  6236.  {
  6237. @@ -5317,33 +5436,4 @@
  6238.  		add_timer_interval(gettick()+1000, parse_console_timer, 0, 0, 1000); //start in 1s each 1sec
  6239.  	}
  6240.  	return 0;
  6241. -}
  6242. -
  6243. -int char_msg_config_read(char *cfgName){
  6244. -	return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
  6245. -}
  6246. -const char* char_msg_txt(int msg_number){
  6247. -	return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
  6248. -}
  6249. -void char_do_final_msg(void){
  6250. -	_do_final_msg(CHAR_MAX_MSG,msg_table);
  6251. -}
  6252. -
  6253. -/*======================================================
  6254. - * Login-Server help option info
  6255. - *------------------------------------------------------*/
  6256. -void display_helpscreen(bool do_exit)
  6257. -{
  6258. -	ShowInfo("Usage: %s [options]\n", SERVER_NAME);
  6259. -	ShowInfo("\n");
  6260. -	ShowInfo("Options:\n");
  6261. -	ShowInfo("  -?, -h [--help]\t\tDisplays this help screen.\n");
  6262. -	ShowInfo("  -v [--version]\t\tDisplays the server's version.\n");
  6263. -	ShowInfo("  --run-once\t\t\tCloses server after loading (testing).\n");
  6264. -	ShowInfo("  --char-config <file>\t\tAlternative char-server configuration.\n");
  6265. -	ShowInfo("  --lan-config <file>\t\tAlternative lag configuration.\n");
  6266. -	ShowInfo("  --inter-config <file>\t\tAlternative inter-server configuration.\n");
  6267. -	ShowInfo("  --msg-config <file>\t\tAlternative message configuration.\n");
  6268. -	if( do_exit )
  6269. -		exit(EXIT_SUCCESS);
  6270. -}
  6271. +}
  6272. \ No newline at end of file
  6273. Index: src/common/timer.c
  6274. ===================================================================
  6275. --- src/common/timer.c	(revision 17365)
  6276. +++ src/common/timer.c	(working copy)
  6277. @@ -109,28 +109,28 @@
  6278.  	} t;
  6279.  
  6280.  	asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1]) );
  6281. -	
  6282. +
  6283.  	return t.qw;
  6284.  }
  6285.  
  6286.  static void rdtsc_calibrate(){
  6287.  	uint64 t1, t2;
  6288.  	int32 i;
  6289. -	
  6290. +
  6291.  	ShowStatus("Calibrating Timer Source, please wait... ");
  6292. -	
  6293. +
  6294.  	RDTSC_CLOCK = 0;
  6295. -	
  6296. +
  6297.  	for(i = 0; i < 5; i++){
  6298.  		t1 = _rdtsc();
  6299.  		usleep(1000000); //1000 MS
  6300.  		t2 = _rdtsc();
  6301. -		RDTSC_CLOCK += (t2 - t1) / 1000; 
  6302. +		RDTSC_CLOCK += (t2 - t1) / 1000;
  6303.  	}
  6304.  	RDTSC_CLOCK /= 5;
  6305. -	
  6306. +
  6307.  	RDTSC_BEGINTICK = _rdtsc();
  6308. -	
  6309. +
  6310.  	ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000) );
  6311.  }
  6312.  
  6313. @@ -243,7 +243,7 @@
  6314.  int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data)
  6315.  {
  6316.  	int tid;
  6317. -	
  6318. +
  6319.  	tid = acquire_timer();
  6320.  	timer_data[tid].tick     = tick;
  6321.  	timer_data[tid].func     = func;
  6322. @@ -267,7 +267,7 @@
  6323.  		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()));
  6324.  		return INVALID_TIMER;
  6325.  	}
  6326. -	
  6327. +
  6328.  	tid = acquire_timer();
  6329.  	timer_data[tid].tick     = tick;
  6330.  	timer_data[tid].func     = func;
  6331. @@ -320,7 +320,7 @@
  6332.  int settick_timer(int tid, unsigned int tick)
  6333.  {
  6334.  	size_t i;
  6335. -	
  6336. +
  6337.  	// search timer position
  6338.  	ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid);
  6339.  	if( i == BHEAP_LENGTH(timer_heap) )
  6340. @@ -406,6 +406,16 @@
  6341.  	return (unsigned long)difftime(time(NULL), start_time);
  6342.  }
  6343.  
  6344. +//-----------------------------------------------------
  6345. +// custom timestamp formatting (from eApp)
  6346. +//-----------------------------------------------------
  6347. +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
  6348. +{
  6349. +	size_t len = strftime(str, size, format, localtime(&timestamp));
  6350. +	memset(str + len, '\0', size - len);
  6351. +	return str;
  6352. +}
  6353. +
  6354.  void timer_init(void)
  6355.  {
  6356.  #if defined(ENABLE_RDTSC)
  6357. Index: src/common/timer.h
  6358. ===================================================================
  6359. --- src/common/timer.h	(revision 17365)
  6360. +++ src/common/timer.h	(working copy)
  6361. @@ -5,6 +5,7 @@
  6362.  #define	_TIMER_H_
  6363.  
  6364.  #include "../common/cbasetypes.h"
  6365. +#include <time.h>
  6366.  
  6367.  #define DIFF_TICK(a,b) ((int)((a)-(b)))
  6368.  
  6369. @@ -51,6 +52,9 @@
  6370.  
  6371.  unsigned long get_uptime(void);
  6372.  
  6373. +//transform a timestamp to string
  6374. +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format);
  6375. +
  6376.  int do_timer(unsigned int tick);
  6377.  void timer_init(void);
  6378.  void timer_final(void);
  6379. Index: src/common/mmo.h
  6380. ===================================================================
  6381. --- src/common/mmo.h	(revision 17365)
  6382. +++ src/common/mmo.h	(working copy)
  6383. @@ -8,47 +8,9 @@
  6384.  #include "../common/db.h"
  6385.  #include <time.h>
  6386.  
  6387. -// server->client protocol version
  6388. -//        0 - pre-?
  6389. -//        1 - ?                    - 0x196
  6390. -//        2 - ?                    - 0x78, 0x79
  6391. -//        3 - ?                    - 0x1c8, 0x1c9, 0x1de
  6392. -//        4 - ?                    - 0x1d7, 0x1d8, 0x1d9, 0x1da
  6393. -//        5 - 2003-12-18aSakexe+   - 0x1ee, 0x1ef, 0x1f0, ?0x1c4, 0x1c5?
  6394. -//        6 - 2004-03-02aSakexe+   - 0x1f4, 0x1f5
  6395. -//        7 - 2005-04-11aSakexe+   - 0x229, 0x22a, 0x22b, 0x22c
  6396. -// 20061023 - 2006-10-23aSakexe+   - 0x6b, 0x6d
  6397. -// 20070521 - 2007-05-21aSakexe+   - 0x283
  6398. -// 20070821 - 2007-08-21aSakexe+   - 0x2c5
  6399. -// 20070918 - 2007-09-18aSakexe+   - 0x2d7, 0x2d9, 0x2da
  6400. -// 20071106 - 2007-11-06aSakexe+   - 0x78, 0x7c, 0x22c
  6401. -// 20080102 - 2008-01-02aSakexe+   - 0x2ec, 0x2ed , 0x2ee
  6402. -// 20081126 - 2008-11-26aSakexe+   - 0x1a2
  6403. -// 20090408 - 2009-04-08aSakexe+   - 0x44a (dont use as it overlaps with RE client packets)
  6404. -// 20080827 - 2008-08-27aRagexeRE+ - First RE Client
  6405. -// 20081217 - 2008-12-17aRagexeRE+ - 0x6d (Note: This one still use old Char Info Packet Structure)
  6406. -// 20081218 - 2008-12-17bRagexeRE+ - 0x6d (Note: From this one client use new Char Info Packet Structure)
  6407. -// 20090603 - 2009-06-03aRagexeRE+ - 0x7d7, 0x7d8, 0x7d9, 0x7da
  6408. -// 20090617 - 2009-06-17aRagexeRE+ - 0x7d9
  6409. -// 20090922 - 2009-09-22aRagexeRE+ - 0x7e5, 0x7e7, 0x7e8, 0x7e9
  6410. -// 20091103 - 2009-11-03aRagexeRE+ - 0x7f7, 0x7f8, 0x7f9
  6411. -// 20100105 - 2010-01-05aRagexeRE+ - 0x133, 0x800, 0x801
  6412. -// 20100126 - 2010-01-26aRagexeRE+ - 0x80e
  6413. -// 20100223 - 2010-02-23aRagexeRE+ - 0x80f
  6414. -// 20100413 - 2010-04-13aRagexeRE+ - 0x6b
  6415. -// 20100629 - 2010-06-29aRagexeRE+ - 0x2d0, 0xaa, 0x2d1, 0x2d2
  6416. -// 20100721 - 2010-07-21aRagexeRE+ - 0x6b, 0x6d
  6417. -// 20100727 - 2010-07-27aRagexeRE+ - 0x6b, 0x6d
  6418. -// 20100803 - 2010-08-03aRagexeRE+ - 0x6b, 0x6d, 0x827, 0x828, 0x829, 0x82a, 0x82b, 0x82c, 0x842, 0x843
  6419. -// 20101124 - 2010-11-24aRagexeRE+ - 0x856, 0x857, 0x858
  6420. -// 20110111 - 2011-01-11aRagexeRE+ - 0x6b, 0x6d
  6421. -// 20110928 - 2011-09-28aRagexeRE+ - 0x6b, 0x6d
  6422. -// 20111025 - 2011-10-25aRagexeRE+ - 0x6b, 0x6d
  6423. -// 20120307 - 2012-03-07aRagexeRE+ - 0x970
  6424. -
  6425.  #ifndef PACKETVER
  6426. -	#define PACKETVER 20120410
  6427. -	//#define PACKETVER 20130320
  6428. +	//#define PACKETVER 20120410
  6429. +	#define PACKETVER 20130320
  6430.  	//#define PACKETVER 20111116
  6431.  #endif
  6432.  
  6433. Index: src/common/utils.c
  6434. ===================================================================
  6435. --- src/common/utils.c	(revision 17365)
  6436. +++ src/common/utils.c	(working copy)
  6437. @@ -109,16 +109,16 @@
  6438.  	WIN32_FIND_DATAA FindFileData;
  6439.  	HANDLE hFind;
  6440.  	char tmppath[MAX_PATH+1];
  6441. -	
  6442. +
  6443.  	const char *path    = (p  ==NULL)? "." : p;
  6444.  	const char *pattern = (pat==NULL)? "" : pat;
  6445. -	
  6446. +
  6447.  	checkpath(tmppath,path);
  6448.  	if( PATHSEP != tmppath[strlen(tmppath)-1])
  6449.  		strcat(tmppath, "\\*");
  6450.  	else
  6451.  		strcat(tmppath, "*");
  6452. -	
  6453. +
  6454.  	hFind = FindFirstFileA(tmppath, &FindFileData);
  6455.  	if (hFind != INVALID_HANDLE_VALUE)
  6456.  	{
  6457. @@ -259,6 +259,46 @@
  6458.  		( (uint32)(word1 << 0x10) );
  6459.  }
  6460.  
  6461. +int date2version(int date){
  6462. +	if(date < 20040906) return 5;
  6463. +	else if(date < 20040920) return 10;
  6464. +	else if(date < 20041005) return 11;
  6465. +	else if(date < 20041025) return 12;
  6466. +	else if(date < 20041129) return 13;
  6467. +	else if(date < 20050110) return 14;
  6468. +	else if(date < 20050509) return 15;
  6469. +	else if(date < 20050628) return 16;
  6470. +	else if(date < 20050718) return 17;
  6471. +	else if(date < 20050719) return 18;
  6472. +	else if(date < 20060327) return 19;
  6473. +	else if(date < 20070108) return 20;
  6474. +	else if(date < 20070212) return 21;
  6475. +	//wtf @FIXME
  6476. +	else if(date < 20080910) return 22;
  6477. +	else if(date < 20080827) return 23;
  6478. +	else if(date < 20080910) return 24;
  6479. +	//unable to solve from date
  6480. +	else if(date < 20101124) return 25;
  6481. +	else if(date < 20111005) return 26;
  6482. +	else if(date < 20111102) return 27;
  6483. +	else if(date < 20120307) return 28;
  6484. +	else if(date < 20120410) return 29;
  6485. +	else if(date < 20120418) return 30;
  6486. +	else if(date < 20120618) return 31;
  6487. +	else if(date < 20120702) return 32;
  6488. +	else if(date < 20130320) return 33;
  6489. +	else if(date < 20130515) return 34;
  6490. +	else if(date < 20130522) return 35;
  6491. +	else if(date < 20130529) return 36;
  6492. +	else if(date < 20130605) return 37;
  6493. +	else if(date < 20130612) return 38;
  6494. +	else if(date >= 20130612) return 39;
  6495. +//	else if(date < 20040920) return 40;
  6496. +//	else if(date < 20040920) return 41;
  6497. +//	else if(date < 20040920) return 42;
  6498. +//	else if(date < 20040920) return 43;
  6499. +	else return 30; //default
  6500. +}
  6501.  
  6502.  /// calculates the value of A / B, in percent (rounded down)
  6503.  unsigned int get_percentage(const unsigned int A, const unsigned int B)
  6504. Index: src/common/utils.h
  6505. ===================================================================
  6506. --- src/common/utils.h	(revision 17365)
  6507. +++ src/common/utils.h	(working copy)
  6508. @@ -29,4 +29,6 @@
  6509.  extern uint16 MakeWord(uint8 byte0, uint8 byte1);
  6510.  extern uint32 MakeDWord(uint16 word0, uint16 word1);
  6511.