viewing paste ra_charrefact | Diff

Posted on the
  1. Index: src/char/char.c
  2. ===================================================================
  3. --- src/char/char.c	(revision 17365)
  4. +++ src/char/char.c	(working copy)
  5. @@ -33,10 +33,9 @@
  6.  #include <stdlib.h>
  7.  #include <malloc.h>
  8.  
  9. -#define MAX_STARTITEM 32
  10. -#define CHAR_MAX_MSG 300
  11. -static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
  12. -
  13. +// <editor-fold defaultstate="collapsed" desc="db_tablename">
  14. +int db_use_sqldbs;
  15. +char db_path[1024] = "db";
  16.  char char_db[256] = "char";
  17.  char scdata_db[256] = "sc_data";
  18.  char cart_db[256] = "cart_inventory";
  19. @@ -67,16 +66,17 @@
  20.  char mercenary_db[256] = "mercenary";
  21.  char mercenary_owner_db[256] = "mercenary_owner";
  22.  char ragsrvinfo_db[256] = "ragsrvinfo";
  23. +// </editor-fold>
  24.  
  25. +
  26.  // show loading/saving messages
  27.  int save_log = 1;
  28.  
  29.  static DBMap* char_db_; // int char_id -> struct mmo_charstatus*
  30.  
  31. -char db_path[1024] = "db";
  32. +#define CHAR_MAX_MSG 300
  33. +static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
  34.  
  35. -int db_use_sqldbs;
  36. -
  37.  struct mmo_map_server {
  38.  	int fd;
  39.  	uint32 ip;
  40. @@ -115,103 +115,90 @@
  41.  int log_char = 1;	// loggin char or not [devil]
  42.  int log_inter = 1;	// loggin inter or not [devil]
  43.  
  44. -// Advanced subnet check [LuzZza]
  45. -struct s_subnet {
  46. -	uint32 mask;
  47. -	uint32 char_ip;
  48. -	uint32 map_ip;
  49. -} subnet[16];
  50. -int subnet_count = 0;
  51. +// check for exit signal
  52. +// 0 is saving complete
  53. +// other is char_id
  54. +unsigned int save_flag = 0;
  55. +// Initial position (it's possible to set it in conf file)
  56. +struct point start_point = { 0, 53, 111 };
  57. +int console = 0;
  58. +int max_connect_user = -1;
  59. +int gm_allow_group = -1;
  60. +int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  61. +int start_zeny = 0;
  62. +int guild_exp_rate = 100;
  63.  
  64. -struct char_session_data {
  65. -	bool auth; // whether the session is authed or not
  66. -	int account_id, login_id1, login_id2, sex;
  67. -	int found_char[MAX_CHARS]; // ids of chars on this account
  68. -	char email[40]; // e-mail (default: a@a.com) by [Yor]
  69. -	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  70. -	int group_id; // permission
  71. -	uint8 char_slots;
  72. -	uint32 version;
  73. -	uint8 clienttype;
  74. -	char new_name[NAME_LENGTH];
  75. -	char birthdate[10+1];  // YYYY-MM-DD
  76. -	// Pincode system
  77. -	char pincode[PINCODE_LENGTH+1];
  78. -	uint32 pincode_seed;
  79. -	time_t pincode_change;
  80. -	uint16 pincode_try;
  81. -	// Addon system
  82. -	unsigned int char_moves[MAX_CHARS]; // character moves left
  83. -};
  84. -
  85. +#define MAX_STARTITEM 32
  86.  struct startitem {
  87.  	int nameid; //Item ID
  88.  	int amount; //Number of items
  89.  	int pos; //Position (for auto-equip)
  90.  } start_items[MAX_STARTITEM+1];
  91.  
  92. -int max_connect_user = -1;
  93. -int gm_allow_group = -1;
  94. -int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  95. -int start_zeny = 0;
  96. -int guild_exp_rate = 100;
  97. -
  98.  // Pincode system
  99. -#define PINCODE_OK 0
  100. -#define PINCODE_ASK 1
  101. -#define PINCODE_NOTSET 2
  102. -#define PINCODE_EXPIRED 3
  103. -#define PINCODE_NEW 4
  104. -#define PINCODE_PASSED 7
  105. -#define	PINCODE_WRONG 8
  106. -
  107. +enum pincode_state {
  108. +	PINCODE_OK = 0,
  109. +	PINCODE_ASK,
  110. +	PINCODE_NOTSET,
  111. +	PINCODE_EXPIRED,
  112. +	PINCODE_NEW,
  113. +	PINCODE_PASSED,
  114. +	PINCODE_WRONG,
  115. +	PINCODE_MAXSTATE
  116. +};
  117.  bool pincode_enabled = true;
  118.  int pincode_changetime = 0;
  119.  int pincode_maxtry = 3;
  120.  bool pincode_force = true;
  121.  
  122. -void pincode_check( int fd, struct char_session_data* sd );
  123. -void pincode_change( int fd, struct char_session_data* sd );
  124. -void pincode_setnew( int fd, struct char_session_data* sd );
  125. -void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state );
  126. -void pincode_notifyLoginPinUpdate( int account_id, char* pin );
  127. -void pincode_notifyLoginPinError( int account_id );
  128. -void pincode_decrypt( uint32 userSeed, char* pin );
  129. -int pincode_compare( int fd, struct char_session_data* sd, char* pin );
  130. -
  131.  // Addon system
  132.  bool char_move_enabled = true;
  133.  bool char_movetoused = true;
  134.  bool char_moves_unlimited = false;
  135.  
  136. -void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to );
  137. -void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason );
  138. -
  139.  //Custom limits for the fame lists. [Skotlex]
  140.  int fame_list_size_chemist = MAX_FAME_LIST;
  141.  int fame_list_size_smith = MAX_FAME_LIST;
  142.  int fame_list_size_taekwon = MAX_FAME_LIST;
  143. -
  144.  // Char-server-side stored fame lists [DracoRPG]
  145.  struct fame_list smith_fame_list[MAX_FAME_LIST];
  146.  struct fame_list chemist_fame_list[MAX_FAME_LIST];
  147.  struct fame_list taekwon_fame_list[MAX_FAME_LIST];
  148.  
  149. -// check for exit signal
  150. -// 0 is saving complete
  151. -// other is char_id
  152. -unsigned int save_flag = 0;
  153.  
  154. -// Initial position (it's possible to set it in conf file)
  155. -struct point start_point = { 0, 53, 111 };
  156. +// Advanced subnet check [LuzZza]
  157. +struct s_subnet {
  158. +	uint32 mask;
  159. +	uint32 char_ip;
  160. +	uint32 map_ip;
  161. +} subnet[16];
  162. +int subnet_count = 0;
  163.  
  164. -int console = 0;
  165. +struct char_session_data {
  166. +	bool auth; // whether the session is authed or not
  167. +	int account_id, login_id1, login_id2, sex;
  168. +	int found_char[MAX_CHARS]; // ids of chars on this account
  169. +	char email[40]; // e-mail (default: a@a.com) by [Yor]
  170. +	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  171. +	int group_id; // permission
  172. +	uint8 char_slots;
  173. +	uint32 version;
  174. +	uint8 clienttype;
  175. +	char new_name[NAME_LENGTH];
  176. +	char birthdate[10+1];  // YYYY-MM-DD
  177. +	// Pincode system
  178. +	char pincode[PINCODE_LENGTH+1];
  179. +	uint32 pincode_seed;
  180. +	time_t pincode_change;
  181. +	uint16 pincode_try;
  182. +	// Addon system
  183. +	unsigned int char_moves[MAX_CHARS]; // character moves left
  184. +};
  185.  
  186.  //-----------------------------------------------------
  187.  // Auth database
  188.  //-----------------------------------------------------
  189.  #define AUTH_TIMEOUT 30000
  190. -
  191.  struct auth_node {
  192.  	int account_id;
  193.  	int char_id;
  194. @@ -223,13 +210,11 @@
  195.  	int group_id;
  196.  	unsigned changing_mapservers : 1;
  197.  };
  198. -
  199.  static DBMap* auth_db; // int account_id -> struct auth_node*
  200.  
  201.  //-----------------------------------------------------
  202.  // Online User Database
  203.  //-----------------------------------------------------
  204. -
  205.  struct online_char_data {
  206.  	int account_id;
  207.  	int char_id;
  208. @@ -238,8 +223,12 @@
  209.  	short server; // -2: unknown server, -1: not connected, 0+: id of server
  210.  	bool pincode_success;
  211.  };
  212. +static DBMap* online_char_db; // int account_id -> struct online_char_data*
  213.  
  214. -static DBMap* online_char_db; // int account_id -> struct online_char_data*
  215. +
  216. +int parse_char(int fd);
  217. +int parse_fromlogin(int fd);
  218. +
  219.  static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
  220.  int delete_char_sql(int char_id);
  221.  
  222. @@ -1951,8 +1940,12 @@
  223.  }
  224.  
  225.  //struct PACKET_CH_CHARLIST_REQ { 0x0 short PacketType}
  226. -void char_parse_req_charlist(int fd, struct char_session_data* sd){
  227. +int char_parse_req_charlist(int fd, struct char_session_data* sd){
  228. +	if( RFIFOREST(fd) < 2 )
  229. +		return 0;
  230. +	RFIFOSKIP(fd,2);
  231.  	mmo_char_send099d(fd,sd);
  232. +	return 1;
  233.  }
  234.  
  235.  //----------------------------------------
  236. @@ -2001,13 +1994,12 @@
  237.  
  238.  void mmo_char_send(int fd, struct char_session_data* sd){
  239.  	ShowInfo("sd->version = %d\n",sd->version);
  240. -#if PACKETVER >= 20130000
  241. +	if(sd->version > 34){
  242.  		mmo_char_send082d(fd,sd);
  243.  		char_charlist_notify(fd,sd);
  244.  		char_block_character(fd,sd);
  245. -#endif
  246. -	//@FIXME dump from kro doesn't show 6b transmission
  247. -	mmo_char_send006b(fd,sd);
  248. +	}
  249. +	mmo_char_send006b(fd,sd); //@FIXME dump from kro doesn't show 6b transmission
  250.  }
  251.  
  252.  int char_married(int pl1, int pl2)
  253. @@ -2184,369 +2176,6 @@
  254.  		ShowStatus("Awaiting maps from map-server.\n");
  255.  }
  256.  
  257. -
  258. -int parse_fromlogin(int fd) {
  259. -	struct char_session_data* sd = NULL;
  260. -	int i;
  261. -
  262. -	// only process data from the login-server
  263. -	if( fd != login_fd ) {
  264. -		ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
  265. -		do_close(fd);
  266. -		return 0;
  267. -	}
  268. -
  269. -	if( session[fd]->flag.eof ) {
  270. -		do_close(fd);
  271. -		login_fd = -1;
  272. -		loginif_on_disconnect();
  273. -		return 0;
  274. -	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
  275. -		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
  276. -			set_eof(fd);
  277. -			return 0;
  278. -		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
  279. -			WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
  280. -			WFIFOW(fd,0) = 0x2719;
  281. -			WFIFOSET(fd,2);
  282. -
  283. -			session[fd]->flag.ping = 2;
  284. -		}
  285. -	}
  286. -
  287. -	sd = (struct char_session_data*)session[fd]->session_data;
  288. -
  289. -	while(RFIFOREST(fd) >= 2) {
  290. -		uint16 command = RFIFOW(fd,0);
  291. -
  292. -		switch( command )
  293. -		{
  294. -
  295. -		// acknowledgement of connect-to-loginserver request
  296. -		case 0x2711:
  297. -			if (RFIFOREST(fd) < 3)
  298. -				return 0;
  299. -
  300. -			if (RFIFOB(fd,2)) {
  301. -				//printf("connect login server error : %d\n", RFIFOB(fd,2));
  302. -				ShowError("Can not connect to login-server.\n");
  303. -				ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  304. -				ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
  305. -				ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
  306. -				set_eof(fd);
  307. -				return 0;
  308. -			} else {
  309. -				ShowStatus("Connected to login-server (connection #%d).\n", fd);
  310. -				loginif_on_ready();
  311. -			}
  312. -			RFIFOSKIP(fd,3);
  313. -		break;
  314. -
  315. -		// acknowledgement of account authentication request
  316. -		case 0x2713:
  317. -			if (RFIFOREST(fd) < 25)
  318. -				return 0;
  319. -		{
  320. -			int account_id = RFIFOL(fd,2);
  321. -			uint32 login_id1 = RFIFOL(fd,6);
  322. -			uint32 login_id2 = RFIFOL(fd,10);
  323. -			uint8 sex = RFIFOB(fd,14);
  324. -			uint8 result = RFIFOB(fd,15);
  325. -			int request_id = RFIFOL(fd,16);
  326. -			uint32 version = RFIFOL(fd,20);
  327. -			uint8 clienttype = RFIFOB(fd,24);
  328. -			RFIFOSKIP(fd,25);
  329. -
  330. -			if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
  331. -				!sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
  332. -			{
  333. -				int client_fd = request_id;
  334. -				sd->version = version;
  335. -				sd->clienttype = clienttype;
  336. -				switch( result )
  337. -				{
  338. -				case 0:// ok
  339. -					char_auth_ok(client_fd, sd);
  340. -					break;
  341. -				case 1:// auth failed
  342. -					WFIFOHEAD(client_fd,3);
  343. -					WFIFOW(client_fd,0) = 0x6c;
  344. -					WFIFOB(client_fd,2) = 0;// rejected from server
  345. -					WFIFOSET(client_fd,3);
  346. -					break;
  347. -				}
  348. -			}
  349. -		}
  350. -		break;
  351. -
  352. -		case 0x2717: // account data
  353. -			if (RFIFOREST(fd) < 72)
  354. -				return 0;
  355. -
  356. -			// find the authenticated session with this account id
  357. -			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) );
  358. -			if( i < fd_max )
  359. -			{
  360. -				int server_id;
  361. -				memcpy(sd->email, RFIFOP(fd,6), 40);
  362. -				sd->expiration_time = (time_t)RFIFOL(fd,46);
  363. -				sd->group_id = RFIFOB(fd,50);
  364. -				sd->char_slots = RFIFOB(fd,51);
  365. -				if( sd->char_slots > MAX_CHARS ) {
  366. -					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);
  367. -					sd->char_slots = MAX_CHARS;/* cap to maximum */
  368. -				} else if ( !sd->char_slots )/* no value aka 0 in sql */
  369. -					sd->char_slots = MAX_CHARS;/* cap to maximum */
  370. -				safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
  371. -				safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
  372. -				sd->pincode_change = (time_t)RFIFOL(fd,68);
  373. -				ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
  374. -				// continued from char_auth_ok...
  375. -				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
  376. -					(max_connect_user == 0 && sd->group_id != gm_allow_group) ||
  377. -					( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
  378. -					// refuse connection (over populated)
  379. -					WFIFOHEAD(i,3);
  380. -					WFIFOW(i,0) = 0x6c;
  381. -					WFIFOW(i,2) = 0;
  382. -					WFIFOSET(i,3);
  383. -				} else {
  384. -					// send characters to player
  385. -					mmo_char_send(i, sd);
  386. -#if PACKETVER >=  20110309
  387. -					if( pincode_enabled ){
  388. -						// PIN code system enabled
  389. -						if( strlen( sd->pincode ) <= 0 ){
  390. -							// No PIN code has been set yet
  391. -							if( pincode_force ){
  392. -								pincode_sendstate( i, sd, PINCODE_NEW );
  393. -							}else{
  394. -								pincode_sendstate( i, sd, PINCODE_PASSED );
  395. -							}
  396. -						}else{
  397. -							if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
  398. -								struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
  399. -
  400. -								if( node != NULL && node->pincode_success ){
  401. -									// User has already passed the check
  402. -									pincode_sendstate( i, sd, PINCODE_PASSED );
  403. -								}else{
  404. -									// Ask user for his PIN code
  405. -									pincode_sendstate( i, sd, PINCODE_ASK );
  406. -								}
  407. -							}else{
  408. -								// User hasnt changed his PIN code too long
  409. -								pincode_sendstate( i, sd, PINCODE_EXPIRED );
  410. -							}
  411. -						}
  412. -					}else{
  413. -						// PIN code system disabled
  414. -						pincode_sendstate( i, sd, PINCODE_OK );
  415. -					}
  416. -#endif
  417. -				}
  418. -			}
  419. -			RFIFOSKIP(fd,72);
  420. -		break;
  421. -
  422. -		// login-server alive packet
  423. -		case 0x2718:
  424. -			if (RFIFOREST(fd) < 2)
  425. -				return 0;
  426. -			RFIFOSKIP(fd,2);
  427. -			session[fd]->flag.ping = 0;
  428. -		break;
  429. -
  430. -		// changesex reply
  431. -		case 0x2723:
  432. -			if (RFIFOREST(fd) < 7)
  433. -				return 0;
  434. -		{
  435. -			unsigned char buf[7];
  436. -
  437. -			int acc = RFIFOL(fd,2);
  438. -			int sex = RFIFOB(fd,6);
  439. -			RFIFOSKIP(fd,7);
  440. -
  441. -			if( acc > 0 )
  442. -			{// TODO: Is this even possible?
  443. -				int char_id[MAX_CHARS];
  444. -				int class_[MAX_CHARS];
  445. -				int guild_id[MAX_CHARS];
  446. -				int num;
  447. -				char* data;
  448. -
  449. -				struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
  450. -				if( node != NULL )
  451. -					node->sex = sex;
  452. -
  453. -				// get characters
  454. -				if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
  455. -					Sql_ShowDebug(sql_handle);
  456. -				for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
  457. -				{
  458. -					Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
  459. -					Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
  460. -					Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
  461. -				}
  462. -				num = i;
  463. -				for( i = 0; i < num; ++i )
  464. -				{
  465. -					if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
  466. -						class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
  467. -						class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
  468. -						class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
  469. -						class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
  470. -						class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
  471. -						class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  472. -					{
  473. -						// job modification
  474. -						if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
  475. -							class_[i] = (sex ? JOB_BARD : JOB_DANCER);
  476. -						else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
  477. -							class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
  478. -						else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
  479. -							class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
  480. -						else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
  481. -							class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
  482. -						else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
  483. -							class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
  484. -						else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
  485. -							class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
  486. -						else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  487. -							class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
  488. -					}
  489. -
  490. -					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]) )
  491. -						Sql_ShowDebug(sql_handle);
  492. -
  493. -					if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
  494. -						inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
  495. -				}
  496. -				Sql_FreeResult(sql_handle);
  497. -
  498. -				// disconnect player if online on char-server
  499. -				disconnect_player(acc);
  500. -			}
  501. -
  502. -			// notify all mapservers about this change
  503. -			WBUFW(buf,0) = 0x2b0d;
  504. -			WBUFL(buf,2) = acc;
  505. -			WBUFB(buf,6) = sex;
  506. -			mapif_sendall(buf, 7);
  507. -		}
  508. -		break;
  509. -
  510. -		// reply to an account_reg2 registry request
  511. -		case 0x2729:
  512. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  513. -				return 0;
  514. -
  515. -		{	//Receive account_reg2 registry, forward to map servers.
  516. -			unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
  517. -			memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  518. -			WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  519. -			mapif_sendall(buf, WBUFW(buf,2));
  520. -			RFIFOSKIP(fd, RFIFOW(fd,2));
  521. -		}
  522. -		break;
  523. -
  524. -		// State change of account/ban notification (from login-server)
  525. -		case 0x2731:
  526. -			if (RFIFOREST(fd) < 11)
  527. -				return 0;
  528. -
  529. -		{	// send to all map-servers to disconnect the player
  530. -			unsigned char buf[11];
  531. -			WBUFW(buf,0) = 0x2b14;
  532. -			WBUFL(buf,2) = RFIFOL(fd,2);
  533. -			WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  534. -			WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  535. -			mapif_sendall(buf, 11);
  536. -		}
  537. -			// disconnect player if online on char-server
  538. -			disconnect_player(RFIFOL(fd,2));
  539. -
  540. -			RFIFOSKIP(fd,11);
  541. -		break;
  542. -
  543. -		// Login server request to kick a character out. [Skotlex]
  544. -		case 0x2734:
  545. -			if (RFIFOREST(fd) < 6)
  546. -				return 0;
  547. -		{
  548. -			int aid = RFIFOL(fd,2);
  549. -			struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
  550. -			RFIFOSKIP(fd,6);
  551. -			if( character != NULL )
  552. -			{// account is already marked as online!
  553. -				if( character->server > -1 )
  554. -				{	//Kick it from the map server it is on.
  555. -					mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  556. -					if (character->waiting_disconnect == INVALID_TIMER)
  557. -						character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
  558. -				}
  559. -				else
  560. -				{// Manual kick from char server.
  561. -					struct char_session_data *tsd;
  562. -					int i;
  563. -					ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
  564. -					if( i < fd_max )
  565. -					{
  566. -						WFIFOHEAD(i,3);
  567. -						WFIFOW(i,0) = 0x81;
  568. -						WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
  569. -						WFIFOSET(i,3);
  570. -						set_eof(i);
  571. -					}
  572. -					else // still moving to the map-server
  573. -						set_char_offline(-1, aid);
  574. -				}
  575. -			}
  576. -			idb_remove(auth_db, aid);// reject auth attempts from map-server
  577. -		}
  578. -		break;
  579. -
  580. -		// ip address update signal from login server
  581. -		case 0x2735:
  582. -		{
  583. -			unsigned char buf[2];
  584. -			uint32 new_ip = 0;
  585. -
  586. -			WBUFW(buf,0) = 0x2b1e;
  587. -			mapif_sendall(buf, 2);
  588. -
  589. -			new_ip = host2ip(login_ip_str);
  590. -			if (new_ip && new_ip != login_ip)
  591. -				login_ip = new_ip; //Update login ip, too.
  592. -
  593. -			new_ip = host2ip(char_ip_str);
  594. -			if (new_ip && new_ip != char_ip)
  595. -			{	//Update ip.
  596. -				char_ip = new_ip;
  597. -				ShowInfo("Updating IP for [%s].\n", char_ip_str);
  598. -				// notify login server about the change
  599. -				WFIFOHEAD(fd,6);
  600. -				WFIFOW(fd,0) = 0x2736;
  601. -				WFIFOL(fd,2) = htonl(char_ip);
  602. -				WFIFOSET(fd,6);
  603. -			}
  604. -
  605. -			RFIFOSKIP(fd,2);
  606. -		}
  607. -		break;
  608. -
  609. -		default:
  610. -			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
  611. -			set_eof(fd);
  612. -			return 0;
  613. -		}
  614. -	}
  615. -
  616. -	RFIFOFLUSH(fd);
  617. -	return 0;
  618. -}
  619. -
  620.  int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data);
  621.  int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
  622.  
  623. @@ -2779,729 +2408,851 @@
  624.  	mapif_server_reset(id);
  625.  }
  626.  
  627. +void do_init_mapif(void)
  628. +{
  629. +	int i;
  630. +	for( i = 0; i < ARRAYLENGTH(server); ++i )
  631. +		mapif_server_init(i);
  632. +}
  633.  
  634. -int parse_frommap(int fd)
  635. +void do_final_mapif(void)
  636.  {
  637. +	int i;
  638. +	for( i = 0; i < ARRAYLENGTH(server); ++i )
  639. +		mapif_server_destroy(i);
  640. +}
  641. +
  642. +// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
  643. +// If found, returns the server's index in the 'server' array (otherwise returns -1).
  644. +int search_mapserver(unsigned short map, uint32 ip, uint16 port)
  645. +{
  646.  	int i, j;
  647. -	int id;
  648.  
  649. -	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  650. -	if( id == ARRAYLENGTH(server) )
  651. -	{// not a map server
  652. -		ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
  653. -		do_close(fd);
  654. -		return 0;
  655. +	for(i = 0; i < ARRAYLENGTH(server); i++)
  656. +	{
  657. +		if (server[i].fd > 0
  658. +		&& (ip == (uint32)-1 || server[i].ip == ip)
  659. +		&& (port == (uint16)-1 || server[i].port == port))
  660. +		{
  661. +			for (j = 0; server[i].map[j]; j++)
  662. +				if (server[i].map[j] == map)
  663. +					return i;
  664. +		}
  665.  	}
  666. -	if( session[fd]->flag.eof )
  667. -	{
  668. -		do_close(fd);
  669. -		server[id].fd = -1;
  670. -		mapif_on_disconnect(id);
  671. +
  672. +	return -1;
  673. +}
  674. +
  675. +// Initialization process (currently only initialization inter_mapif)
  676. +static int char_mapif_init(int fd)
  677. +{
  678. +	return inter_mapif_init(fd);
  679. +}
  680. +
  681. +//--------------------------------------------
  682. +// Test to know if an IP come from LAN or WAN.
  683. +//--------------------------------------------
  684. +int lan_subnetcheck(uint32 ip)
  685. +{
  686. +	int i;
  687. +	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  688. +	if( i < subnet_count ) {
  689. +		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));
  690. +		return subnet[i].map_ip;
  691. +	} else {
  692. +		ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
  693.  		return 0;
  694.  	}
  695. +}
  696.  
  697. -	while(RFIFOREST(fd) >= 2){
  698. -		switch(RFIFOW(fd,0)){
  699.  
  700. -		case 0x2afa: // Receiving map names list from the map-server
  701. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  702. -				return 0;
  703. +//For use in packets that depend on an sd being present [Skotlex]
  704. +#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
  705.  
  706. -			memset(server[id].map, 0, sizeof(server[id].map));
  707. -			j = 0;
  708. -			for(i = 4; i < RFIFOW(fd,2); i += 4) {
  709. -				server[id].map[j] = RFIFOW(fd,i);
  710. -				j++;
  711. -			}
  712. +///
  713. +/// Map IF
  714. +///
  715.  
  716. -			ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  717. -						id, j, CONVIP(server[id].ip), server[id].port);
  718. -			ShowStatus("Map-server %d loading complete.\n", id);
  719. +int char_parsemap_getmapname(int fd, int id){
  720. +	int j = 0, i = 0;
  721. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  722. +		return 0;
  723.  
  724. -			// send name for wisp to player
  725. -			WFIFOHEAD(fd, 3 + NAME_LENGTH);
  726. -			WFIFOW(fd,0) = 0x2afb;
  727. -			WFIFOB(fd,2) = 0;
  728. -			memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
  729. -			WFIFOSET(fd,3+NAME_LENGTH);
  730. +	memset(server[id].map, 0, sizeof(server[id].map));
  731. +	for(i = 4; i < RFIFOW(fd,2); i += 4) {
  732. +		server[id].map[j] = RFIFOW(fd,i);
  733. +		j++;
  734. +	}
  735.  
  736. -			char_send_fame_list(fd); //Send fame list.
  737. +	ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  738. +				id, j, CONVIP(server[id].ip), server[id].port);
  739. +	ShowStatus("Map-server %d loading complete.\n", id);
  740.  
  741. -			{
  742. -			unsigned char buf[16384];
  743. -			int x;
  744. -			if (j == 0) {
  745. -				ShowWarning("Map-server %d has NO maps.\n", id);
  746. -			} else {
  747. -				// Transmitting maps information to the other map-servers
  748. -				WBUFW(buf,0) = 0x2b04;
  749. -				WBUFW(buf,2) = j * 4 + 10;
  750. -				WBUFL(buf,4) = htonl(server[id].ip);
  751. -				WBUFW(buf,8) = htons(server[id].port);
  752. -				memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
  753. -				mapif_sendallwos(fd, buf, WBUFW(buf,2));
  754. -			}
  755. -			// Transmitting the maps of the other map-servers to the new map-server
  756. -			for(x = 0; x < ARRAYLENGTH(server); x++) {
  757. -				if (server[x].fd > 0 && x != id) {
  758. -					WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
  759. -					WFIFOW(fd,0) = 0x2b04;
  760. -					WFIFOL(fd,4) = htonl(server[x].ip);
  761. -					WFIFOW(fd,8) = htons(server[x].port);
  762. -					j = 0;
  763. -					for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
  764. -						if (server[x].map[i])
  765. -							WFIFOW(fd,10+(j++)*4) = server[x].map[i];
  766. -					if (j > 0) {
  767. -						WFIFOW(fd,2) = j * 4 + 10;
  768. -						WFIFOSET(fd,WFIFOW(fd,2));
  769. -					}
  770. +	// send name for wisp to player
  771. +	WFIFOHEAD(fd, 3 + NAME_LENGTH);
  772. +	WFIFOW(fd,0) = 0x2afb;
  773. +	WFIFOB(fd,2) = 0;
  774. +	memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
  775. +	WFIFOSET(fd,3+NAME_LENGTH);
  776. +
  777. +	char_send_fame_list(fd); //Send fame list.
  778. +
  779. +	{
  780. +		unsigned char buf[16384];
  781. +		int x;
  782. +		if (j == 0) {
  783. +			ShowWarning("Map-server %d has NO maps.\n", id);
  784. +		} else {
  785. +			// Transmitting maps information to the other map-servers
  786. +			WBUFW(buf,0) = 0x2b04;
  787. +			WBUFW(buf,2) = j * 4 + 10;
  788. +			WBUFL(buf,4) = htonl(server[id].ip);
  789. +			WBUFW(buf,8) = htons(server[id].port);
  790. +			memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
  791. +			mapif_sendallwos(fd, buf, WBUFW(buf,2));
  792. +		}
  793. +		// Transmitting the maps of the other map-servers to the new map-server
  794. +		for(x = 0; x < ARRAYLENGTH(server); x++) {
  795. +			if (server[x].fd > 0 && x != id) {
  796. +				WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
  797. +				WFIFOW(fd,0) = 0x2b04;
  798. +				WFIFOL(fd,4) = htonl(server[x].ip);
  799. +				WFIFOW(fd,8) = htons(server[x].port);
  800. +				j = 0;
  801. +				for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
  802. +					if (server[x].map[i])
  803. +						WFIFOW(fd,10+(j++)*4) = server[x].map[i];
  804. +				if (j > 0) {
  805. +					WFIFOW(fd,2) = j * 4 + 10;
  806. +					WFIFOSET(fd,WFIFOW(fd,2));
  807.  				}
  808.  			}
  809. -			}
  810. -			RFIFOSKIP(fd,RFIFOW(fd,2));
  811. -		break;
  812. +		}
  813. +	}
  814. +	RFIFOSKIP(fd,RFIFOW(fd,2));
  815. +	return 1;
  816. +}
  817.  
  818. -		case 0x2afc: //Packet command is now used for sc_data request. [Skotlex]
  819. -			if (RFIFOREST(fd) < 10)
  820. -				return 0;
  821. +int char_parsemap_askscdata(int fd, int id){
  822. +	if (RFIFOREST(fd) < 10)
  823. +		return 0;
  824. +	{
  825. +#ifdef ENABLE_SC_SAVING
  826. +		int aid, cid;
  827. +		aid = RFIFOL(fd,2);
  828. +		cid = RFIFOL(fd,6);
  829. +		if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
  830. +			scdata_db, aid, cid) )
  831.  		{
  832. -#ifdef ENABLE_SC_SAVING
  833. -			int aid, cid;
  834. -			aid = RFIFOL(fd,2);
  835. -			cid = RFIFOL(fd,6);
  836. -			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
  837. -				scdata_db, aid, cid) )
  838. +			Sql_ShowDebug(sql_handle);
  839. +			return 0;
  840. +		}
  841. +		if( Sql_NumRows(sql_handle) > 0 )
  842. +		{
  843. +			struct status_change_data scdata;
  844. +			int count;
  845. +			char* data;
  846. +
  847. +			WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
  848. +			WFIFOW(fd,0) = 0x2b1d;
  849. +			WFIFOL(fd,4) = aid;
  850. +			WFIFOL(fd,8) = cid;
  851. +			for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
  852.  			{
  853. -				Sql_ShowDebug(sql_handle);
  854. -				break;
  855. +				Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
  856. +				Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
  857. +				Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
  858. +				Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
  859. +				Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
  860. +				Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
  861. +				memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
  862.  			}
  863. -			if( Sql_NumRows(sql_handle) > 0 )
  864. +			if (count >= 50)
  865. +				ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
  866. +			if (count > 0)
  867.  			{
  868. -				struct status_change_data scdata;
  869. -				int count;
  870. -				char* data;
  871. +				WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
  872. +				WFIFOW(fd,12) = count;
  873. +				WFIFOSET(fd,WFIFOW(fd,2));
  874.  
  875. -				WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
  876. -				WFIFOW(fd,0) = 0x2b1d;
  877. -				WFIFOL(fd,4) = aid;
  878. -				WFIFOL(fd,8) = cid;
  879. -				for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
  880. -				{
  881. -					Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
  882. -					Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
  883. -					Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
  884. -					Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
  885. -					Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
  886. -					Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
  887. -					memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
  888. -				}
  889. -				if (count >= 50)
  890. -					ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
  891. -				if (count > 0)
  892. -				{
  893. -					WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
  894. -					WFIFOW(fd,12) = count;
  895. -					WFIFOSET(fd,WFIFOW(fd,2));
  896. -
  897. -					//Clear the data once loaded.
  898. -					if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
  899. -						Sql_ShowDebug(sql_handle);
  900. -				}
  901. +				//Clear the data once loaded.
  902. +				if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
  903. +					Sql_ShowDebug(sql_handle);
  904.  			}
  905. -			Sql_FreeResult(sql_handle);
  906. +		}
  907. +		Sql_FreeResult(sql_handle);
  908.  #endif
  909. -			RFIFOSKIP(fd, 10);
  910. -		}
  911. -		break;
  912. +		RFIFOSKIP(fd, 10);
  913. +	}
  914. +	return 1;
  915. +}
  916.  
  917. -		case 0x2afe: //set MAP user count
  918. -			if (RFIFOREST(fd) < 4)
  919. -				return 0;
  920. -			if (RFIFOW(fd,2) != server[id].users) {
  921. -				server[id].users = RFIFOW(fd,2);
  922. -				ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
  923. -			}
  924. -			RFIFOSKIP(fd, 4);
  925. -			break;
  926. +int char_parsemap_getusercount(int fd, int id){
  927. +	if (RFIFOREST(fd) < 4)
  928. +		return 0;
  929. +	if (RFIFOW(fd,2) != server[id].users) {
  930. +		server[id].users = RFIFOW(fd,2);
  931. +		ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
  932. +	}
  933. +	RFIFOSKIP(fd, 4);
  934. +	return 1;
  935. +}
  936.  
  937. -		case 0x2aff: //set MAP users
  938. -			if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  939. -				return 0;
  940. -		{
  941. -			//TODO: When data mismatches memory, update guild/party online/offline states.
  942. -			int aid, cid;
  943. -			struct online_char_data* character;
  944. +int char_parsemap_regmapuser(int fd, int id){
  945. +	int i;
  946. +	if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  947. +		return 0;
  948. +	{
  949. +		//TODO: When data mismatches memory, update guild/party online/offline states.
  950. +		int aid, cid;
  951. +		struct online_char_data* character;
  952.  
  953. -			server[id].users = RFIFOW(fd,4);
  954. -			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
  955. -			for(i = 0; i < server[id].users; i++) {
  956. -				aid = RFIFOL(fd,6+i*8);
  957. -				cid = RFIFOL(fd,6+i*8+4);
  958. -				character = idb_ensure(online_char_db, aid, create_online_char_data);
  959. -				if( character->server > -1 && character->server != id )
  960. -				{
  961. -					ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
  962. -						character->account_id, character->char_id, character->server, id, aid, cid);
  963. -					mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  964. -				}
  965. -				character->server = id;
  966. -				character->char_id = cid;
  967. +		server[id].users = RFIFOW(fd,4);
  968. +		online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
  969. +		for(i = 0; i < server[id].users; i++) {
  970. +			aid = RFIFOL(fd,6+i*8);
  971. +			cid = RFIFOL(fd,6+i*8+4);
  972. +			character = idb_ensure(online_char_db, aid, create_online_char_data);
  973. +			if( character->server > -1 && character->server != id )
  974. +			{
  975. +				ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
  976. +					character->account_id, character->char_id, character->server, id, aid, cid);
  977. +				mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  978.  			}
  979. -			//If any chars remain in -2, they will be cleaned in the cleanup timer.
  980. -			RFIFOSKIP(fd,RFIFOW(fd,2));
  981. +			character->server = id;
  982. +			character->char_id = cid;
  983.  		}
  984. -		break;
  985. +		//If any chars remain in -2, they will be cleaned in the cleanup timer.
  986. +		RFIFOSKIP(fd,RFIFOW(fd,2));
  987. +	}
  988. +	return 1;
  989. +}
  990.  
  991. -		case 0x2b01: // Receive character data from map-server for saving
  992. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  993. -				return 0;
  994. +int char_parsemap_reqsavechar(int fd, int id){
  995. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  996. +			return 0;
  997. +	{
  998. +		int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
  999. +		struct online_char_data* character;
  1000. +
  1001. +		if (size - 13 != sizeof(struct mmo_charstatus))
  1002.  		{
  1003. -			int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
  1004. -			struct online_char_data* character;
  1005. -
  1006. -			if (size - 13 != sizeof(struct mmo_charstatus))
  1007. -			{
  1008. -				ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
  1009. -				RFIFOSKIP(fd,size);
  1010. -				break;
  1011. -			}
  1012. -			//Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
  1013. -			if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
  1014. -				(character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
  1015. -				character->char_id == cid))
  1016. -			{
  1017. -				struct mmo_charstatus char_dat;
  1018. -				memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
  1019. -				mmo_char_tosql(cid, &char_dat);
  1020. -			} else {	//This may be valid on char-server reconnection, when re-sending characters that already logged off.
  1021. -				ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
  1022. -				set_char_online(id, cid, aid);
  1023. -			}
  1024. -
  1025. -			if (RFIFOB(fd,12))
  1026. -			{	//Flag, set character offline after saving. [Skotlex]
  1027. -				set_char_offline(cid, aid);
  1028. -				WFIFOHEAD(fd,10);
  1029. -				WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
  1030. -				WFIFOL(fd,2) = aid;
  1031. -				WFIFOL(fd,6) = cid;
  1032. -				WFIFOSET(fd,10);
  1033. -			}
  1034. +			ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
  1035.  			RFIFOSKIP(fd,size);
  1036. +			return 0;
  1037.  		}
  1038. -		break;
  1039. +		//Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
  1040. +		if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
  1041. +			(character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
  1042. +			character->char_id == cid))
  1043. +		{
  1044. +			struct mmo_charstatus char_dat;
  1045. +			memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
  1046. +			mmo_char_tosql(cid, &char_dat);
  1047. +		} else {	//This may be valid on char-server reconnection, when re-sending characters that already logged off.
  1048. +			ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
  1049. +			set_char_online(id, cid, aid);
  1050. +		}
  1051.  
  1052. -		case 0x2b02: // req char selection
  1053. -			if( RFIFOREST(fd) < 18 )
  1054. -				return 0;
  1055. -			else{
  1056. -				int account_id = RFIFOL(fd,2);
  1057. -				uint32 login_id1 = RFIFOL(fd,6);
  1058. -				uint32 login_id2 = RFIFOL(fd,10);
  1059. -				uint32 ip = RFIFOL(fd,14);
  1060. -				RFIFOSKIP(fd,18);
  1061. +		if (RFIFOB(fd,12))
  1062. +		{	//Flag, set character offline after saving. [Skotlex]
  1063. +			set_char_offline(cid, aid);
  1064. +			WFIFOHEAD(fd,10);
  1065. +			WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
  1066. +			WFIFOL(fd,2) = aid;
  1067. +			WFIFOL(fd,6) = cid;
  1068. +			WFIFOSET(fd,10);
  1069. +		}
  1070. +		RFIFOSKIP(fd,size);
  1071. +	}
  1072. +	return 1;
  1073. +}
  1074.  
  1075. -				if( runflag != CHARSERVER_ST_RUNNING ){
  1076. -					WFIFOHEAD(fd,7);
  1077. -					WFIFOW(fd,0) = 0x2b03;
  1078. -					WFIFOL(fd,2) = account_id;
  1079. -					WFIFOB(fd,6) = 0;// not ok
  1080. -					WFIFOSET(fd,7);
  1081. -				}else{
  1082. -					struct auth_node* node;
  1083. +int char_parsemap_authok(int fd, int id){
  1084. +	if( RFIFOREST(fd) < 18 )
  1085. +		return 0;
  1086. +	else{
  1087. +		int account_id = RFIFOL(fd,2);
  1088. +		uint32 login_id1 = RFIFOL(fd,6);
  1089. +		uint32 login_id2 = RFIFOL(fd,10);
  1090. +		uint32 ip = RFIFOL(fd,14);
  1091. +		RFIFOSKIP(fd,18);
  1092.  
  1093. -					// create temporary auth entry
  1094. -					CREATE(node, struct auth_node, 1);
  1095. -					node->account_id = account_id;
  1096. -					node->char_id = 0;
  1097. -					node->login_id1 = login_id1;
  1098. -					node->login_id2 = login_id2;
  1099. -					//node->sex = 0;
  1100. -					node->ip = ntohl(ip);
  1101. -					//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
  1102. -					//node->gmlevel = 0;
  1103. -					idb_put(auth_db, account_id, node);
  1104. +		if( runflag != CHARSERVER_ST_RUNNING ){
  1105. +			WFIFOHEAD(fd,7);
  1106. +			WFIFOW(fd,0) = 0x2b03;
  1107. +			WFIFOL(fd,2) = account_id;
  1108. +			WFIFOB(fd,6) = 0;// not ok
  1109. +			WFIFOSET(fd,7);
  1110. +		}else{
  1111. +			struct auth_node* node;
  1112.  
  1113. -					//Set char to "@ char select" in online db [Kevin]
  1114. -					set_char_charselect(account_id);
  1115. +			// create temporary auth entry
  1116. +			CREATE(node, struct auth_node, 1);
  1117. +			node->account_id = account_id;
  1118. +			node->char_id = 0;
  1119. +			node->login_id1 = login_id1;
  1120. +			node->login_id2 = login_id2;
  1121. +			//node->sex = 0;
  1122. +			node->ip = ntohl(ip);
  1123. +			//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
  1124. +			//node->gmlevel = 0;
  1125. +			idb_put(auth_db, account_id, node);
  1126.  
  1127. -					{
  1128. -						struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
  1129. +			//Set char to "@ char select" in online db [Kevin]
  1130. +			set_char_charselect(account_id);
  1131.  
  1132. -						if( character != NULL ){
  1133. -							character->pincode_success = true;
  1134. -						}
  1135. -					}
  1136. +			{
  1137. +				struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
  1138.  
  1139. -					WFIFOHEAD(fd,7);
  1140. -					WFIFOW(fd,0) = 0x2b03;
  1141. -					WFIFOL(fd,2) = account_id;
  1142. -					WFIFOB(fd,6) = 1;// ok
  1143. -					WFIFOSET(fd,7);
  1144. +				if( character != NULL ){
  1145. +					character->pincode_success = true;
  1146.  				}
  1147.  			}
  1148. -		break;
  1149.  
  1150. -		case 0x2b05: // request "change map server"
  1151. -			if (RFIFOREST(fd) < 39)
  1152. -				return 0;
  1153. -		{
  1154. -			int map_id, map_fd = -1;
  1155. -			struct mmo_charstatus* char_data;
  1156. -			struct mmo_charstatus char_dat;
  1157. +			WFIFOHEAD(fd,7);
  1158. +			WFIFOW(fd,0) = 0x2b03;
  1159. +			WFIFOL(fd,2) = account_id;
  1160. +			WFIFOB(fd,6) = 1;// ok
  1161. +			WFIFOSET(fd,7);
  1162. +		}
  1163. +	}
  1164. +	return 1;
  1165. +}
  1166.  
  1167. -			map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
  1168. -			if (map_id >= 0)
  1169. -				map_fd = server[map_id].fd;
  1170. -			//Char should just had been saved before this packet, so this should be safe. [Skotlex]
  1171. +int char_parsemap_reqchangemapserv(int fd, int id){
  1172. +	if (RFIFOREST(fd) < 39)
  1173. +		return 0;
  1174. +	{
  1175. +		int map_id, map_fd = -1;
  1176. +		struct mmo_charstatus* char_data;
  1177. +		struct mmo_charstatus char_dat;
  1178. +
  1179. +		map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
  1180. +		if (map_id >= 0)
  1181. +			map_fd = server[map_id].fd;
  1182. +		//Char should just had been saved before this packet, so this should be safe. [Skotlex]
  1183. +		char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  1184. +		if (char_data == NULL) {	//Really shouldn't happen.
  1185. +			mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
  1186.  			char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  1187. -			if (char_data == NULL) {	//Really shouldn't happen.
  1188. -				mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
  1189. -				char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
  1190. -			}
  1191. +		}
  1192.  
  1193. -			if( runflag == CHARSERVER_ST_RUNNING &&
  1194. -				session_isActive(map_fd) &&
  1195. -				char_data )
  1196. -			{	//Send the map server the auth of this player.
  1197. -				struct online_char_data* data;
  1198. -				struct auth_node* node;
  1199. +		if( runflag == CHARSERVER_ST_RUNNING &&
  1200. +			session_isActive(map_fd) &&
  1201. +			char_data )
  1202. +		{	//Send the map server the auth of this player.
  1203. +			struct online_char_data* data;
  1204. +			struct auth_node* node;
  1205.  
  1206. -				//Update the "last map" as this is where the player must be spawned on the new map server.
  1207. -				char_data->last_point.map = RFIFOW(fd,18);
  1208. -				char_data->last_point.x = RFIFOW(fd,20);
  1209. -				char_data->last_point.y = RFIFOW(fd,22);
  1210. -				char_data->sex = RFIFOB(fd,30);
  1211. +			//Update the "last map" as this is where the player must be spawned on the new map server.
  1212. +			char_data->last_point.map = RFIFOW(fd,18);
  1213. +			char_data->last_point.x = RFIFOW(fd,20);
  1214. +			char_data->last_point.y = RFIFOW(fd,22);
  1215. +			char_data->sex = RFIFOB(fd,30);
  1216.  
  1217. -				// create temporary auth entry
  1218. -				CREATE(node, struct auth_node, 1);
  1219. -				node->account_id = RFIFOL(fd,2);
  1220. -				node->char_id = RFIFOL(fd,14);
  1221. -				node->login_id1 = RFIFOL(fd,6);
  1222. -				node->login_id2 = RFIFOL(fd,10);
  1223. -				node->sex = RFIFOB(fd,30);
  1224. -				node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
  1225. -				node->ip = ntohl(RFIFOL(fd,31));
  1226. -				node->group_id = RFIFOL(fd,35);
  1227. -				node->changing_mapservers = 1;
  1228. -				idb_put(auth_db, RFIFOL(fd,2), node);
  1229. +			// create temporary auth entry
  1230. +			CREATE(node, struct auth_node, 1);
  1231. +			node->account_id = RFIFOL(fd,2);
  1232. +			node->char_id = RFIFOL(fd,14);
  1233. +			node->login_id1 = RFIFOL(fd,6);
  1234. +			node->login_id2 = RFIFOL(fd,10);
  1235. +			node->sex = RFIFOB(fd,30);
  1236. +			node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
  1237. +			node->ip = ntohl(RFIFOL(fd,31));
  1238. +			node->group_id = RFIFOL(fd,35);
  1239. +			node->changing_mapservers = 1;
  1240. +			idb_put(auth_db, RFIFOL(fd,2), node);
  1241.  
  1242. -				data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
  1243. -				data->char_id = char_data->char_id;
  1244. -				data->server = map_id; //Update server where char is.
  1245. +			data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
  1246. +			data->char_id = char_data->char_id;
  1247. +			data->server = map_id; //Update server where char is.
  1248.  
  1249. -				//Reply with an ack.
  1250. -				WFIFOHEAD(fd,30);
  1251. -				WFIFOW(fd,0) = 0x2b06;
  1252. -				memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  1253. -				WFIFOSET(fd,30);
  1254. -			} else { //Reply with nak
  1255. -				WFIFOHEAD(fd,30);
  1256. -				WFIFOW(fd,0) = 0x2b06;
  1257. -				memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  1258. -				WFIFOL(fd,6) = 0; //Set login1 to 0.
  1259. -				WFIFOSET(fd,30);
  1260. -			}
  1261. -			RFIFOSKIP(fd,39);
  1262. +			//Reply with an ack.
  1263. +			WFIFOHEAD(fd,30);
  1264. +			WFIFOW(fd,0) = 0x2b06;
  1265. +			memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  1266. +			WFIFOSET(fd,30);
  1267. +		} else { //Reply with nak
  1268. +			WFIFOHEAD(fd,30);
  1269. +			WFIFOW(fd,0) = 0x2b06;
  1270. +			memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  1271. +			WFIFOL(fd,6) = 0; //Set login1 to 0.
  1272. +			WFIFOSET(fd,30);
  1273.  		}
  1274. -		break;
  1275. +		RFIFOSKIP(fd,39);
  1276. +	}
  1277. +	return 1;
  1278. +}
  1279.  
  1280. -		case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
  1281. -			if (RFIFOREST(fd) < 10)
  1282. -				return 0;
  1283. -			{
  1284. -				int char_id, friend_id;
  1285. -				char_id = RFIFOL(fd,2);
  1286. -				friend_id = RFIFOL(fd,6);
  1287. -				if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
  1288. -					friend_db, char_id, friend_id) ) {
  1289. -					Sql_ShowDebug(sql_handle);
  1290. -					break;
  1291. -				}
  1292. -				RFIFOSKIP(fd,10);
  1293. -			}
  1294. -		break;
  1295. +int char_parsemap_askrmfriend(int fd, int id){
  1296. +	if (RFIFOREST(fd) < 10)
  1297. +		return 0;
  1298. +	{
  1299. +		int char_id, friend_id;
  1300. +		char_id = RFIFOL(fd,2);
  1301. +		friend_id = RFIFOL(fd,6);
  1302. +		if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
  1303. +			friend_db, char_id, friend_id) ) {
  1304. +			Sql_ShowDebug(sql_handle);
  1305. +			return 0;
  1306. +		}
  1307. +		RFIFOSKIP(fd,10);
  1308. +	}
  1309. +	return 1;
  1310. +}
  1311.  
  1312. -		case 0x2b08: // char name request
  1313. -			if (RFIFOREST(fd) < 6)
  1314. -				return 0;
  1315. +int char_parsemap_reqcharname(int fd, int id){
  1316. +	if (RFIFOREST(fd) < 6)
  1317. +		return 0;
  1318.  
  1319. -			WFIFOHEAD(fd,30);
  1320. -			WFIFOW(fd,0) = 0x2b09;
  1321. -			WFIFOL(fd,2) = RFIFOL(fd,2);
  1322. -			char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
  1323. -			WFIFOSET(fd,30);
  1324. +	WFIFOHEAD(fd,30);
  1325. +	WFIFOW(fd,0) = 0x2b09;
  1326. +	WFIFOL(fd,2) = RFIFOL(fd,2);
  1327. +	char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
  1328. +	WFIFOSET(fd,30);
  1329.  
  1330. -			RFIFOSKIP(fd,6);
  1331. -		break;
  1332. +	RFIFOSKIP(fd,6);
  1333. +	return 1;
  1334. +}
  1335.  
  1336. -		case 0x2b0c: // Map server send information to change an email of an account -> login-server
  1337. -			if (RFIFOREST(fd) < 86)
  1338. -				return 0;
  1339. -			if (login_fd > 0) { // don't send request if no login-server
  1340. -				WFIFOHEAD(login_fd,86);
  1341. -				memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  1342. -				WFIFOW(login_fd,0) = 0x2722;
  1343. -				WFIFOSET(login_fd,86);
  1344. -			}
  1345. -			RFIFOSKIP(fd, 86);
  1346. -		break;
  1347. +int char_parsemap_reqnewemail(int fd, int id){
  1348. +	if (RFIFOREST(fd) < 86)
  1349. +		return 0;
  1350. +	if (login_fd > 0) { // don't send request if no login-server
  1351. +		WFIFOHEAD(login_fd,86);
  1352. +		memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  1353. +		WFIFOW(login_fd,0) = 0x2722;
  1354. +		WFIFOSET(login_fd,86);
  1355. +	}
  1356. +	RFIFOSKIP(fd, 86);
  1357. +	return 1;
  1358. +}
  1359.  
  1360. -		case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server)
  1361. -			if (RFIFOREST(fd) < 44)
  1362. -				return 0;
  1363. -		{
  1364. -			int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
  1365. -			char esc_name[NAME_LENGTH*2+1];
  1366. +int char_parsemap_fwlog_changestatus(int fd, int id){
  1367. +	if (RFIFOREST(fd) < 44)
  1368. +		return 0;
  1369. +	{
  1370. +		int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
  1371. +		char esc_name[NAME_LENGTH*2+1];
  1372.  
  1373. -			int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
  1374. -			const char* name = (char*)RFIFOP(fd,6); // name of the target character
  1375. -			int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
  1376. -			short year = RFIFOW(fd,32);
  1377. -			short month = RFIFOW(fd,34);
  1378. -			short day = RFIFOW(fd,36);
  1379. -			short hour = RFIFOW(fd,38);
  1380. -			short minute = RFIFOW(fd,40);
  1381. -			short second = RFIFOW(fd,42);
  1382. -			RFIFOSKIP(fd,44);
  1383. +		int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
  1384. +		const char* name = (char*)RFIFOP(fd,6); // name of the target character
  1385. +		int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
  1386. +		short year = RFIFOW(fd,32);
  1387. +		short month = RFIFOW(fd,34);
  1388. +		short day = RFIFOW(fd,36);
  1389. +		short hour = RFIFOW(fd,38);
  1390. +		short minute = RFIFOW(fd,40);
  1391. +		short second = RFIFOW(fd,42);
  1392. +		RFIFOSKIP(fd,44);
  1393.  
  1394. -			Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  1395. -			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
  1396. -				Sql_ShowDebug(sql_handle);
  1397. -			else
  1398. -			if( Sql_NumRows(sql_handle) == 0 )
  1399. -			{
  1400. -				result = 1; // 1-player not found
  1401. -			}
  1402. -			else
  1403. -			if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  1404. -				Sql_ShowDebug(sql_handle);
  1405. -				//FIXME: set proper result value?
  1406. -			else
  1407. -			{
  1408. -				char name[NAME_LENGTH];
  1409. -				int account_id;
  1410. -				char* data;
  1411. +		Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  1412. +		if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
  1413. +			Sql_ShowDebug(sql_handle);
  1414. +		else
  1415. +		if( Sql_NumRows(sql_handle) == 0 )
  1416. +		{
  1417. +			result = 1; // 1-player not found
  1418. +		}
  1419. +		else
  1420. +		if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  1421. +			Sql_ShowDebug(sql_handle);
  1422. +			//FIXME: set proper result value?
  1423. +		else
  1424. +		{
  1425. +			char name[NAME_LENGTH];
  1426. +			int account_id;
  1427. +			char* data;
  1428.  
  1429. -				Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
  1430. -				Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
  1431. +			Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
  1432. +			Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
  1433.  
  1434. -				if( login_fd <= 0 )
  1435. -					result = 3; // 3-login-server offline
  1436. -				//FIXME: need to move this check to login server [ultramage]
  1437. +			if( login_fd <= 0 )
  1438. +				result = 3; // 3-login-server offline
  1439. +			//FIXME: need to move this check to login server [ultramage]
  1440.  //				else
  1441.  //				if( acc != -1 && isGM(acc) < isGM(account_id) )
  1442.  //					result = 2; // 2-gm level too low
  1443. -				else
  1444. -				switch( type ) {
  1445. -				case 1: // block
  1446. -						WFIFOHEAD(login_fd,10);
  1447. -						WFIFOW(login_fd,0) = 0x2724;
  1448. -						WFIFOL(login_fd,2) = account_id;
  1449. -						WFIFOL(login_fd,6) = 5; // new account status
  1450. -						WFIFOSET(login_fd,10);
  1451. -				break;
  1452. -				case 2: // ban
  1453. -						WFIFOHEAD(login_fd,18);
  1454. -						WFIFOW(login_fd, 0) = 0x2725;
  1455. -						WFIFOL(login_fd, 2) = account_id;
  1456. -						WFIFOW(login_fd, 6) = year;
  1457. -						WFIFOW(login_fd, 8) = month;
  1458. -						WFIFOW(login_fd,10) = day;
  1459. -						WFIFOW(login_fd,12) = hour;
  1460. -						WFIFOW(login_fd,14) = minute;
  1461. -						WFIFOW(login_fd,16) = second;
  1462. -						WFIFOSET(login_fd,18);
  1463. -				break;
  1464. -				case 3: // unblock
  1465. -						WFIFOHEAD(login_fd,10);
  1466. -						WFIFOW(login_fd,0) = 0x2724;
  1467. -						WFIFOL(login_fd,2) = account_id;
  1468. -						WFIFOL(login_fd,6) = 0; // new account status
  1469. -						WFIFOSET(login_fd,10);
  1470. -				break;
  1471. -				case 4: // unban
  1472. -						WFIFOHEAD(login_fd,6);
  1473. -						WFIFOW(login_fd,0) = 0x272a;
  1474. -						WFIFOL(login_fd,2) = account_id;
  1475. -						WFIFOSET(login_fd,6);
  1476. -				break;
  1477. -				case 5: // changesex
  1478. -						WFIFOHEAD(login_fd,6);
  1479. -						WFIFOW(login_fd,0) = 0x2727;
  1480. -						WFIFOL(login_fd,2) = account_id;
  1481. -						WFIFOSET(login_fd,6);
  1482. -				break;
  1483. -				}
  1484. +			else
  1485. +			switch( type ) {
  1486. +			case 1: // block
  1487. +					WFIFOHEAD(login_fd,10);
  1488. +					WFIFOW(login_fd,0) = 0x2724;
  1489. +					WFIFOL(login_fd,2) = account_id;
  1490. +					WFIFOL(login_fd,6) = 5; // new account status
  1491. +					WFIFOSET(login_fd,10);
  1492. +			break;
  1493. +			case 2: // ban
  1494. +					WFIFOHEAD(login_fd,18);
  1495. +					WFIFOW(login_fd, 0) = 0x2725;
  1496. +					WFIFOL(login_fd, 2) = account_id;
  1497. +					WFIFOW(login_fd, 6) = year;
  1498. +					WFIFOW(login_fd, 8) = month;
  1499. +					WFIFOW(login_fd,10) = day;
  1500. +					WFIFOW(login_fd,12) = hour;
  1501. +					WFIFOW(login_fd,14) = minute;
  1502. +					WFIFOW(login_fd,16) = second;
  1503. +					WFIFOSET(login_fd,18);
  1504. +			break;
  1505. +			case 3: // unblock
  1506. +					WFIFOHEAD(login_fd,10);
  1507. +					WFIFOW(login_fd,0) = 0x2724;
  1508. +					WFIFOL(login_fd,2) = account_id;
  1509. +					WFIFOL(login_fd,6) = 0; // new account status
  1510. +					WFIFOSET(login_fd,10);
  1511. +			break;
  1512. +			case 4: // unban
  1513. +					WFIFOHEAD(login_fd,6);
  1514. +					WFIFOW(login_fd,0) = 0x272a;
  1515. +					WFIFOL(login_fd,2) = account_id;
  1516. +					WFIFOSET(login_fd,6);
  1517. +			break;
  1518. +			case 5: // changesex
  1519. +					WFIFOHEAD(login_fd,6);
  1520. +					WFIFOW(login_fd,0) = 0x2727;
  1521. +					WFIFOL(login_fd,2) = account_id;
  1522. +					WFIFOSET(login_fd,6);
  1523. +			break;
  1524.  			}
  1525. +		}
  1526.  
  1527. -			Sql_FreeResult(sql_handle);
  1528. +		Sql_FreeResult(sql_handle);
  1529.  
  1530. -			// send answer if a player ask, not if the server ask
  1531. -			if( acc != -1 && type != 5) { // Don't send answer for changesex
  1532. -				WFIFOHEAD(fd,34);
  1533. -				WFIFOW(fd, 0) = 0x2b0f;
  1534. -				WFIFOL(fd, 2) = acc;
  1535. -				safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
  1536. -				WFIFOW(fd,30) = type;
  1537. -				WFIFOW(fd,32) = result;
  1538. -				WFIFOSET(fd,34);
  1539. -			}
  1540. +		// send answer if a player ask, not if the server ask
  1541. +		if( acc != -1 && type != 5) { // Don't send answer for changesex
  1542. +			WFIFOHEAD(fd,34);
  1543. +			WFIFOW(fd, 0) = 0x2b0f;
  1544. +			WFIFOL(fd, 2) = acc;
  1545. +			safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
  1546. +			WFIFOW(fd,30) = type;
  1547. +			WFIFOW(fd,32) = result;
  1548. +			WFIFOSET(fd,34);
  1549.  		}
  1550. -		break;
  1551. +	}
  1552. +	return 1;
  1553. +}
  1554.  
  1555. -		case 0x2b10: // Update and send fame ranking list
  1556. -			if (RFIFOREST(fd) < 11)
  1557. -				return 0;
  1558. +int char_parsemap_updfamelist(int fd, int id){
  1559. +	if (RFIFOREST(fd) < 11)
  1560. +		return 0;
  1561. +	{
  1562. +		int cid = RFIFOL(fd, 2);
  1563. +		int fame = RFIFOL(fd, 6);
  1564. +		char type = RFIFOB(fd, 10);
  1565. +		int size;
  1566. +		struct fame_list* list;
  1567. +		int player_pos;
  1568. +		int fame_pos;
  1569. +
  1570. +		switch(type)
  1571.  		{
  1572. -			int cid = RFIFOL(fd, 2);
  1573. -			int fame = RFIFOL(fd, 6);
  1574. -			char type = RFIFOB(fd, 10);
  1575. -			int size;
  1576. -			struct fame_list* list;
  1577. -			int player_pos;
  1578. -			int fame_pos;
  1579. +			case 1:  size = fame_list_size_smith;   list = smith_fame_list;   break;
  1580. +			case 2:  size = fame_list_size_chemist; list = chemist_fame_list; break;
  1581. +			case 3:  size = fame_list_size_taekwon; list = taekwon_fame_list; break;
  1582. +			default: size = 0;                      list = NULL;              break;
  1583. +		}
  1584.  
  1585. -			switch(type)
  1586. -			{
  1587. -				case 1:  size = fame_list_size_smith;   list = smith_fame_list;   break;
  1588. -				case 2:  size = fame_list_size_chemist; list = chemist_fame_list; break;
  1589. -				case 3:  size = fame_list_size_taekwon; list = taekwon_fame_list; break;
  1590. -				default: size = 0;                      list = NULL;              break;
  1591. -			}
  1592. +		ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
  1593. +		ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
  1594.  
  1595. -			ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
  1596. -			ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
  1597. -
  1598. -			if( player_pos == size && fame_pos == size )
  1599. -				;// not on list and not enough fame to get on it
  1600. -			else if( fame_pos == player_pos )
  1601. -			{// same position
  1602. -				list[player_pos].fame = fame;
  1603. -				char_update_fame_list(type, player_pos, fame);
  1604. +		if( player_pos == size && fame_pos == size )
  1605. +			;// not on list and not enough fame to get on it
  1606. +		else if( fame_pos == player_pos )
  1607. +		{// same position
  1608. +			list[player_pos].fame = fame;
  1609. +			char_update_fame_list(type, player_pos, fame);
  1610. +		}
  1611. +		else
  1612. +		{// move in the list
  1613. +			if( player_pos == size )
  1614. +			{// new ranker - not in the list
  1615. +				ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
  1616. +				list[fame_pos].id = cid;
  1617. +				list[fame_pos].fame = fame;
  1618. +				char_loadName(cid, list[fame_pos].name);
  1619.  			}
  1620.  			else
  1621. -			{// move in the list
  1622. -				if( player_pos == size )
  1623. -				{// new ranker - not in the list
  1624. -					ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
  1625. -					list[fame_pos].id = cid;
  1626. -					list[fame_pos].fame = fame;
  1627. -					char_loadName(cid, list[fame_pos].name);
  1628. -				}
  1629. -				else
  1630. -				{// already in the list
  1631. -					if( fame_pos == size )
  1632. -						--fame_pos;// move to the end of the list
  1633. -					ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
  1634. -					list[fame_pos].fame = fame;
  1635. -				}
  1636. -				char_send_fame_list(-1);
  1637. +			{// already in the list
  1638. +				if( fame_pos == size )
  1639. +					--fame_pos;// move to the end of the list
  1640. +				ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
  1641. +				list[fame_pos].fame = fame;
  1642.  			}
  1643. -
  1644. -			RFIFOSKIP(fd,11);
  1645. +			char_send_fame_list(-1);
  1646.  		}
  1647. -		break;
  1648.  
  1649. -		// Divorce chars
  1650. -		case 0x2b11:
  1651. -			if( RFIFOREST(fd) < 10 )
  1652. -				return 0;
  1653. -			divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
  1654. -			RFIFOSKIP(fd,10);
  1655. -		break;
  1656. +		RFIFOSKIP(fd,11);
  1657. +	}
  1658. +	return 1;
  1659. +}
  1660.  
  1661. -		case 0x2b16: // Receive rates [Wizputer]
  1662. -			if( RFIFOREST(fd) < 14 )
  1663. -				return 0;
  1664. -		{
  1665. -			char esc_server_name[sizeof(server_name)*2+1];
  1666. +int char_parsemap_reqdivorce(int fd, int id){
  1667. +	if( RFIFOREST(fd) < 10 )
  1668. +		return 0;
  1669. +	divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
  1670. +	RFIFOSKIP(fd,10);
  1671. +	return 1;
  1672. +}
  1673. +int char_parsemap_updmapinfo(int fd, int id){
  1674. +	if( RFIFOREST(fd) < 14 )
  1675. +		return 0;
  1676. +	{
  1677. +		char esc_server_name[sizeof(server_name)*2+1];
  1678.  
  1679. -			Sql_EscapeString(sql_handle, esc_server_name, server_name);
  1680. +		Sql_EscapeString(sql_handle, esc_server_name, server_name);
  1681.  
  1682. -			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
  1683. -				ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
  1684. -				Sql_ShowDebug(sql_handle);
  1685. -			RFIFOSKIP(fd,14);
  1686. -		}
  1687. -		break;
  1688. +		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
  1689. +			ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
  1690. +			Sql_ShowDebug(sql_handle);
  1691. +		RFIFOSKIP(fd,14);
  1692. +	}
  1693. +	return 1;
  1694. +}
  1695. +int char_parsemap_setcharoffline(int fd, int id){
  1696. +	if (RFIFOREST(fd) < 6)
  1697. +		return 0;
  1698. +	set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
  1699. +	RFIFOSKIP(fd,10);
  1700. +	return 1;
  1701. +}
  1702. +int char_parsemap_setalloffline(int fd, int id){
  1703. +	set_all_offline(id);
  1704. +	RFIFOSKIP(fd,2);
  1705. +	return 1;
  1706. +}
  1707. +int char_parsemap_setcharonline(int fd, int id){
  1708. +	if (RFIFOREST(fd) < 10)
  1709. +		return 0;
  1710. +	set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
  1711. +	RFIFOSKIP(fd,10);
  1712. +	return 1;
  1713. +}
  1714. +int char_parsemap_reqfamelist(int fd, int id){
  1715. +	if (RFIFOREST(fd) < 2)
  1716. +		return 0;
  1717. +	char_read_fame_list();
  1718. +	char_send_fame_list(-1);
  1719. +	RFIFOSKIP(fd,2);
  1720. +	return 1;
  1721. +}
  1722.  
  1723. -		case 0x2b17: // Character disconnected set online 0 [Wizputer]
  1724. -			if (RFIFOREST(fd) < 6)
  1725. -				return 0;
  1726. -			set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
  1727. -			RFIFOSKIP(fd,10);
  1728. -		break;
  1729. +int char_parsemap_save_scdata(int fd, int id){
  1730. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1731. +		return 0;
  1732. +	{
  1733. +#ifdef ENABLE_SC_SAVING
  1734. +		int count, aid, cid;
  1735.  
  1736. -		case 0x2b18: // Reset all chars to offline [Wizputer]
  1737. -			set_all_offline(id);
  1738. -			RFIFOSKIP(fd,2);
  1739. -		break;
  1740. +		aid = RFIFOL(fd, 4);
  1741. +		cid = RFIFOL(fd, 8);
  1742. +		count = RFIFOW(fd, 12);
  1743.  
  1744. -		case 0x2b19: // Character set online [Wizputer]
  1745. -			if (RFIFOREST(fd) < 10)
  1746. -				return 0;
  1747. -			set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
  1748. -			RFIFOSKIP(fd,10);
  1749. -		break;
  1750. -
  1751. -		case 0x2b1a: // Build and send fame ranking lists [DracoRPG]
  1752. -			if (RFIFOREST(fd) < 2)
  1753. -				return 0;
  1754. -			char_read_fame_list();
  1755. -			char_send_fame_list(-1);
  1756. -			RFIFOSKIP(fd,2);
  1757. -		break;
  1758. -
  1759. -		case 0x2b1c: //Request to save status change data. [Skotlex]
  1760. -			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1761. -				return 0;
  1762. +		if( count > 0 )
  1763.  		{
  1764. -#ifdef ENABLE_SC_SAVING
  1765. -			int count, aid, cid;
  1766. +			struct status_change_data data;
  1767. +			StringBuf buf;
  1768. +			int i;
  1769.  
  1770. -			aid = RFIFOL(fd, 4);
  1771. -			cid = RFIFOL(fd, 8);
  1772. -			count = RFIFOW(fd, 12);
  1773. -
  1774. -			if( count > 0 )
  1775. +			StringBuf_Init(&buf);
  1776. +			StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
  1777. +			for( i = 0; i < count; ++i )
  1778.  			{
  1779. -				struct status_change_data data;
  1780. -				StringBuf buf;
  1781. -				int i;
  1782. -
  1783. -				StringBuf_Init(&buf);
  1784. -				StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
  1785. -				for( i = 0; i < count; ++i )
  1786. -				{
  1787. -					memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
  1788. -					if( i > 0 )
  1789. -						StringBuf_AppendStr(&buf, ", ");
  1790. -					StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
  1791. -						data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
  1792. -				}
  1793. -				if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
  1794. -					Sql_ShowDebug(sql_handle);
  1795. -				StringBuf_Destroy(&buf);
  1796. +				memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
  1797. +				if( i > 0 )
  1798. +					StringBuf_AppendStr(&buf, ", ");
  1799. +				StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
  1800. +					data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
  1801.  			}
  1802. +			if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
  1803. +				Sql_ShowDebug(sql_handle);
  1804. +			StringBuf_Destroy(&buf);
  1805. +		}
  1806.  #endif
  1807. -			RFIFOSKIP(fd, RFIFOW(fd, 2));
  1808. -		}
  1809. -		break;
  1810. +		RFIFOSKIP(fd, RFIFOW(fd, 2));
  1811. +	}
  1812. +	return 1;
  1813. +}
  1814.  
  1815. -		case 0x2b23: // map-server alive packet
  1816. -			WFIFOHEAD(fd,2);
  1817. -			WFIFOW(fd,0) = 0x2b24;
  1818. -			WFIFOSET(fd,2);
  1819. -			RFIFOSKIP(fd,2);
  1820. -		break;
  1821. +int char_parsemap_keepalive(int fd, int id){
  1822. +	WFIFOHEAD(fd,2);
  1823. +	WFIFOW(fd,0) = 0x2b24;
  1824. +	WFIFOSET(fd,2);
  1825. +	RFIFOSKIP(fd,2);
  1826. +	return 1;
  1827. +}
  1828.  
  1829. -		case 0x2b26: // auth request from map-server
  1830. -			if (RFIFOREST(fd) < 19)
  1831. -				return 0;
  1832. +int char_parsemap_reqauth(int fd, int id){
  1833. +	if (RFIFOREST(fd) < 19)
  1834. +		return 0;
  1835.  
  1836. -		{
  1837. -			int account_id;
  1838. -			int char_id;
  1839. -			int login_id1;
  1840. -			char sex;
  1841. -			uint32 ip;
  1842. -			struct auth_node* node;
  1843. -			struct mmo_charstatus* cd;
  1844. -			struct mmo_charstatus char_dat;
  1845. +	{
  1846. +		int account_id;
  1847. +		int char_id;
  1848. +		int login_id1;
  1849. +		char sex;
  1850. +		uint32 ip;
  1851. +		struct auth_node* node;
  1852. +		struct mmo_charstatus* cd;
  1853. +		struct mmo_charstatus char_dat;
  1854.  
  1855. -			account_id = RFIFOL(fd,2);
  1856. -			char_id    = RFIFOL(fd,6);
  1857. -			login_id1  = RFIFOL(fd,10);
  1858. -			sex        = RFIFOB(fd,14);
  1859. -			ip         = ntohl(RFIFOL(fd,15));
  1860. -			RFIFOSKIP(fd,19);
  1861. +		account_id = RFIFOL(fd,2);
  1862. +		char_id    = RFIFOL(fd,6);
  1863. +		login_id1  = RFIFOL(fd,10);
  1864. +		sex        = RFIFOB(fd,14);
  1865. +		ip         = ntohl(RFIFOL(fd,15));
  1866. +		RFIFOSKIP(fd,19);
  1867.  
  1868. -			node = (struct auth_node*)idb_get(auth_db, account_id);
  1869. +		node = (struct auth_node*)idb_get(auth_db, account_id);
  1870. +		cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  1871. +		if( cd == NULL )
  1872. +		{	//Really shouldn't happen.
  1873. +			mmo_char_fromsql(char_id, &char_dat, true);
  1874.  			cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  1875. -			if( cd == NULL )
  1876. -			{	//Really shouldn't happen.
  1877. -				mmo_char_fromsql(char_id, &char_dat, true);
  1878. -				cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
  1879. -			}
  1880. -			if( runflag == CHARSERVER_ST_RUNNING &&
  1881. -				cd != NULL &&
  1882. -				node != NULL &&
  1883. -				node->account_id == account_id &&
  1884. -				node->char_id == char_id &&
  1885. -				node->login_id1 == login_id1 &&
  1886. -				node->sex == sex /*&&
  1887. -				node->ip == ip*/ )
  1888. -			{// auth ok
  1889. -				cd->sex = sex;
  1890. +		}
  1891. +		if( runflag == CHARSERVER_ST_RUNNING &&
  1892. +			cd != NULL &&
  1893. +			node != NULL &&
  1894. +			node->account_id == account_id &&
  1895. +			node->char_id == char_id &&
  1896. +			node->login_id1 == login_id1 &&
  1897. +			node->sex == sex /*&&
  1898. +			node->ip == ip*/ )
  1899. +		{// auth ok
  1900. +			cd->sex = sex;
  1901.  
  1902. -				WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
  1903. -				WFIFOW(fd,0) = 0x2afd;
  1904. -				WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
  1905. -				WFIFOL(fd,4) = account_id;
  1906. -				WFIFOL(fd,8) = node->login_id1;
  1907. -				WFIFOL(fd,12) = node->login_id2;
  1908. -				WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
  1909. -				WFIFOL(fd,20) = node->group_id;
  1910. -				WFIFOB(fd,24) = node->changing_mapservers;
  1911. -				memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
  1912. -				WFIFOSET(fd, WFIFOW(fd,2));
  1913. +			WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
  1914. +			WFIFOW(fd,0) = 0x2afd;
  1915. +			WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
  1916. +			WFIFOL(fd,4) = account_id;
  1917. +			WFIFOL(fd,8) = node->login_id1;
  1918. +			WFIFOL(fd,12) = node->login_id2;
  1919. +			WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
  1920. +			WFIFOL(fd,20) = node->group_id;
  1921. +			WFIFOB(fd,24) = node->changing_mapservers;
  1922. +			memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
  1923. +			WFIFOSET(fd, WFIFOW(fd,2));
  1924.  
  1925. -				// only use the auth once and mark user online
  1926. -				idb_remove(auth_db, account_id);
  1927. -				set_char_online(id, char_id, account_id);
  1928. -			}
  1929. -			else
  1930. -			{// auth failed
  1931. -				WFIFOHEAD(fd,19);
  1932. -				WFIFOW(fd,0) = 0x2b27;
  1933. -				WFIFOL(fd,2) = account_id;
  1934. -				WFIFOL(fd,6) = char_id;
  1935. -				WFIFOL(fd,10) = login_id1;
  1936. -				WFIFOB(fd,14) = sex;
  1937. -				WFIFOL(fd,15) = htonl(ip);
  1938. -				WFIFOSET(fd,19);
  1939. -			}
  1940. +			// only use the auth once and mark user online
  1941. +			idb_remove(auth_db, account_id);
  1942. +			set_char_online(id, char_id, account_id);
  1943.  		}
  1944. -		break;
  1945. +		else
  1946. +		{// auth failed
  1947. +			WFIFOHEAD(fd,19);
  1948. +			WFIFOW(fd,0) = 0x2b27;
  1949. +			WFIFOL(fd,2) = account_id;
  1950. +			WFIFOL(fd,6) = char_id;
  1951. +			WFIFOL(fd,10) = login_id1;
  1952. +			WFIFOB(fd,14) = sex;
  1953. +			WFIFOL(fd,15) = htonl(ip);
  1954. +			WFIFOSET(fd,19);
  1955. +		}
  1956. +	}
  1957. +	return 1;
  1958. +}
  1959.  
  1960. -		case 0x2736: // ip address update
  1961. -			if (RFIFOREST(fd) < 6) return 0;
  1962. -			server[id].ip = ntohl(RFIFOL(fd, 2));
  1963. -			ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
  1964. -			RFIFOSKIP(fd,6);
  1965. -		break;
  1966. +int char_parsemap_updmapip(int fd, int id){
  1967. +	if (RFIFOREST(fd) < 6) return 0;
  1968. +	server[id].ip = ntohl(RFIFOL(fd, 2));
  1969. +	ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
  1970. +	RFIFOSKIP(fd,6);
  1971. +	return 1;
  1972. +}
  1973.  
  1974. -		case 0x3008:
  1975. -			if( RFIFOREST(fd) < RFIFOW(fd,4) )
  1976. -				return 0;/* packet wasn't fully received yet (still fragmented) */
  1977. -			else {
  1978. -				int sfd;/* stat server fd */
  1979. -				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 */
  1980. +int char_parsemap_fw_configstats(int fd, int id){
  1981. +	if( RFIFOREST(fd) < RFIFOW(fd,4) )
  1982. +		return 0;/* packet wasn't fully received yet (still fragmented) */
  1983. +	else {
  1984. +		int sfd;/* stat server fd */
  1985. +		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 */
  1986.  
  1987. -				if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
  1988. -					RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  1989. -					break;/* connection not possible, we drop the report */
  1990. -				}
  1991. -
  1992. -				session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
  1993. -				WFIFOHEAD(sfd, RFIFOW(fd,2) );
  1994. -				memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
  1995. -				WFIFOSET(sfd, RFIFOW(fd,2) );
  1996. -				flush_fifo(sfd);
  1997. -				do_close(sfd);
  1998. -				RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  1999. +		if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
  2000. +			RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  2001. +			return 0;/* connection not possible, we drop the report */
  2002.  		}
  2003. -		break;
  2004.  
  2005. +		session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
  2006. +		WFIFOHEAD(sfd, RFIFOW(fd,2) );
  2007. +		memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
  2008. +		WFIFOSET(sfd, RFIFOW(fd,2) );
  2009. +		flush_fifo(sfd);
  2010. +		do_close(sfd);
  2011. +		RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
  2012. +	}
  2013. +	return 1;
  2014. +}
  2015. +
  2016. +int parse_frommap(int fd){
  2017. +	int id; //mapserv id
  2018. +	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
  2019. +	if( id == ARRAYLENGTH(server) )
  2020. +	{// not a map server
  2021. +		ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
  2022. +		do_close(fd);
  2023. +		return 0;
  2024. +	}
  2025. +	if( session[fd]->flag.eof )
  2026. +	{
  2027. +		do_close(fd);
  2028. +		server[id].fd = -1;
  2029. +		mapif_on_disconnect(id);
  2030. +		return 0;
  2031. +	}
  2032. +
  2033. +	while(RFIFOREST(fd) >= 2){
  2034. +		switch(RFIFOW(fd,0)){
  2035. +		// Receiving map names list from the map-server
  2036. +		case 0x2afa: char_parsemap_getmapname(fd,id); break;
  2037. +		//Packet command is now used for sc_data request. [Skotlex]
  2038. +		case 0x2afc: char_parsemap_askscdata(fd,id); break;
  2039. +		//MAP user count
  2040. +		case 0x2afe: char_parsemap_getusercount(fd,id); break; //get nb user
  2041. +		case 0x2aff: char_parsemap_regmapuser(fd,id); break; //register users
  2042. +		// Receive character data from map-server for saving
  2043. +		case 0x2b01: char_parsemap_reqsavechar(fd,id); break;
  2044. +		// req char selection;
  2045. +		case 0x2b02: char_parsemap_authok(fd,id); break;
  2046. +		// request "change map server"
  2047. +		case 0x2b05: char_parsemap_reqchangemapserv(fd,id); break;
  2048. +		// Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
  2049. +		case 0x2b07: char_parsemap_askrmfriend(fd,id); break;
  2050. +		// char name request
  2051. +		case 0x2b08: char_parsemap_reqcharname(fd,id); break;
  2052. +		// Map server send information to change an email of an account -> login-server
  2053. +		case 0x2b0c: char_parsemap_reqnewemail(fd,id); break;
  2054. +		// Request from map-server to change an account's status (will just be forwarded to login server)
  2055. +		case 0x2b0e: char_parsemap_fwlog_changestatus(fd,id); break;
  2056. +		// Update and send fame ranking list
  2057. +		case 0x2b10: char_parsemap_updfamelist(fd,id); break;
  2058. +		// Divorce chars
  2059. +		case 0x2b11: char_parsemap_reqdivorce(fd,id); break;
  2060. +		// Receive rates [Wizputer]
  2061. +		case 0x2b16: char_parsemap_updmapinfo(fd,id); break;
  2062. +		// Character disconnected set online 0 [Wizputer]
  2063. +		case 0x2b17: char_parsemap_setcharoffline(fd,id); break;
  2064. +		// Reset all chars to offline [Wizputer]
  2065. +		case 0x2b18: char_parsemap_setalloffline(fd,id); break;
  2066. +		// Character set online [Wizputer]
  2067. +		case 0x2b19: char_parsemap_setcharonline(fd,id); break;
  2068. +		// Build and send fame ranking lists [DracoRPG]
  2069. +		case 0x2b1a: char_parsemap_reqfamelist(fd,id); break;
  2070. +		//Request to save status change data. [Skotlex]
  2071. +		case 0x2b1c: char_parsemap_save_scdata(fd,id); break;
  2072. +		// map-server alive packet
  2073. +		case 0x2b23: char_parsemap_keepalive(fd,id); break;
  2074. +		// auth request from map-server
  2075. +		case 0x2b26: char_parsemap_reqauth(fd,id); break;
  2076. +		// ip address update
  2077. +		case 0x2736: char_parsemap_updmapip(fd,id); break;
  2078. +		// transmit emu usage for anom stats
  2079. +		case 0x3008: char_parsemap_fw_configstats(fd,id); break;
  2080.  		default:
  2081.  		{
  2082.  			// inter server - packet
  2083.  			int r = inter_parse_frommap(fd);
  2084.  			if (r == 1) break;		// processed
  2085.  			if (r == 2) return 0;	// need more packet
  2086. -
  2087.  			// no inter server packet. no char server packet -> disconnect
  2088.  			ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
  2089.  			set_eof(fd);
  2090. @@ -3513,64 +3264,10 @@
  2091.  	return 0;
  2092.  }
  2093.  
  2094. -void do_init_mapif(void)
  2095. -{
  2096. -	int i;
  2097. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  2098. -		mapif_server_init(i);
  2099. -}
  2100. +//
  2101. +// Client IF
  2102. +//
  2103.  
  2104. -void do_final_mapif(void)
  2105. -{
  2106. -	int i;
  2107. -	for( i = 0; i < ARRAYLENGTH(server); ++i )
  2108. -		mapif_server_destroy(i);
  2109. -}
  2110. -
  2111. -// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
  2112. -// If found, returns the server's index in the 'server' array (otherwise returns -1).
  2113. -int search_mapserver(unsigned short map, uint32 ip, uint16 port)
  2114. -{
  2115. -	int i, j;
  2116. -
  2117. -	for(i = 0; i < ARRAYLENGTH(server); i++)
  2118. -	{
  2119. -		if (server[i].fd > 0
  2120. -		&& (ip == (uint32)-1 || server[i].ip == ip)
  2121. -		&& (port == (uint16)-1 || server[i].port == port))
  2122. -		{
  2123. -			for (j = 0; server[i].map[j]; j++)
  2124. -				if (server[i].map[j] == map)
  2125. -					return i;
  2126. -		}
  2127. -	}
  2128. -
  2129. -	return -1;
  2130. -}
  2131. -
  2132. -// Initialization process (currently only initialization inter_mapif)
  2133. -static int char_mapif_init(int fd)
  2134. -{
  2135. -	return inter_mapif_init(fd);
  2136. -}
  2137. -
  2138. -//--------------------------------------------
  2139. -// Test to know if an IP come from LAN or WAN.
  2140. -//--------------------------------------------
  2141. -int lan_subnetcheck(uint32 ip)
  2142. -{
  2143. -	int i;
  2144. -	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  2145. -	if( i < subnet_count ) {
  2146. -		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));
  2147. -		return subnet[i].map_ip;
  2148. -	} else {
  2149. -		ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
  2150. -		return 0;
  2151. -	}
  2152. -}
  2153. -
  2154. -
  2155.  /// @param result
  2156.  /// 0 (0x718): An unknown error has occurred.
  2157.  /// 1: none/success
  2158. @@ -3588,7 +3285,6 @@
  2159.  	WFIFOSET(fd,14);
  2160.  }
  2161.  
  2162. -
  2163.  /// @param result
  2164.  /// 0 (0x718): An unknown error has occurred.
  2165.  /// 1: none/success
  2166. @@ -3606,7 +3302,6 @@
  2167.  	WFIFOSET(fd,10);
  2168.  }
  2169.  
  2170. -
  2171.  /// @param result
  2172.  /// 1 (0x718): none/success, (if char id not in deletion process): An unknown error has occurred.
  2173.  /// 2 (0x719): A database error occurred.
  2174. @@ -3620,34 +3315,37 @@
  2175.  	WFIFOSET(fd,10);
  2176.  }
  2177.  
  2178. -
  2179. -static void char_delete2_req(int fd, struct char_session_data* sd)
  2180. -{// CH: <0827>.W <char id>.L
  2181. +// CH: <0827>.W <char id>.L
  2182. +int char_parse_delete2_req(int fd, struct char_session_data* sd)
  2183. +{
  2184.  	int char_id, i;
  2185.  	char* data;
  2186.  	time_t delete_date;
  2187.  
  2188. +	FIFOSD_CHECK(6)
  2189. +
  2190.  	char_id = RFIFOL(fd,2);
  2191. +	RFIFOSKIP(fd,6);
  2192.  
  2193.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  2194.  	if( i == MAX_CHARS )
  2195.  	{// character not found
  2196.  		char_delete2_ack(fd, char_id, 3, 0);
  2197. -		return;
  2198. +		return 0;
  2199.  	}
  2200.  
  2201.  	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) )
  2202.  	{
  2203.  		Sql_ShowDebug(sql_handle);
  2204.  		char_delete2_ack(fd, char_id, 3, 0);
  2205. -		return;
  2206. +		return 0;
  2207.  	}
  2208.  
  2209.  	Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10);
  2210.  
  2211.  	if( delete_date ) {// character already queued for deletion
  2212.  		char_delete2_ack(fd, char_id, 0, 0);
  2213. -		return;
  2214. +		return 0;
  2215.  	}
  2216.  
  2217.  /*
  2218. @@ -3674,14 +3372,14 @@
  2219.  	{
  2220.  		Sql_ShowDebug(sql_handle);
  2221.  		char_delete2_ack(fd, char_id, 3, 0);
  2222. -		return;
  2223. +		return 0;
  2224.  	}
  2225.  
  2226.  	char_delete2_ack(fd, char_id, 1, delete_date);
  2227. +	return 1;
  2228.  }
  2229.  
  2230. -
  2231. -static void char_delete2_accept(int fd, struct char_session_data* sd)
  2232. +int char_parse_delete2_accept(int fd, struct char_session_data* sd)
  2233.  {// CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
  2234.  	char birthdate[8+1];
  2235.  	int char_id, i, k;
  2236. @@ -3689,6 +3387,8 @@
  2237.  	char* data;
  2238.  	time_t delete_date;
  2239.  
  2240. +	FIFOSD_CHECK(12)
  2241. +
  2242.  	char_id = RFIFOL(fd,2);
  2243.  
  2244.  	ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id);
  2245. @@ -3703,19 +3403,20 @@
  2246.  	birthdate[6] = RFIFOB(fd,10);
  2247.  	birthdate[7] = RFIFOB(fd,11);
  2248.  	birthdate[8] = 0;
  2249. +	RFIFOSKIP(fd,12);
  2250.  
  2251.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  2252.  	if( i == MAX_CHARS )
  2253.  	{// character not found
  2254.  		char_delete2_accept_ack(fd, char_id, 3);
  2255. -		return;
  2256. +		return 0;
  2257.  	}
  2258.  
  2259.  	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) )
  2260.  	{// data error
  2261.  		Sql_ShowDebug(sql_handle);
  2262.  		char_delete2_accept_ack(fd, char_id, 3);
  2263. -		return;
  2264. +		return 0;
  2265.  	}
  2266.  
  2267.  	Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10);
  2268. @@ -3724,26 +3425,26 @@
  2269.  	if( !delete_date || delete_date>time(NULL) )
  2270.  	{// not queued or delay not yet passed
  2271.  		char_delete2_accept_ack(fd, char_id, 4);
  2272. -		return;
  2273. +		return 0;
  2274.  	}
  2275.  
  2276.  	if( strcmp(sd->birthdate+2, birthdate) )  // +2 to cut off the century
  2277.  	{// birth date is wrong
  2278.  		char_delete2_accept_ack(fd, char_id, 5);
  2279. -		return;
  2280. +		return 0;
  2281.  	}
  2282.  
  2283.  	if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) )
  2284.  	{// character level config restriction
  2285.  		char_delete2_accept_ack(fd, char_id, 2);
  2286. -		return;
  2287. +		return 0;
  2288.  	}
  2289.  
  2290.  	// success
  2291.  	if( delete_char_sql(char_id) < 0 )
  2292.  	{
  2293.  		char_delete2_accept_ack(fd, char_id, 3);
  2294. -		return;
  2295. +		return 0;
  2296.  	}
  2297.  
  2298.  	// refresh character list cache
  2299. @@ -3754,20 +3455,24 @@
  2300.  	sd->found_char[MAX_CHARS-1] = -1;
  2301.  
  2302.  	char_delete2_accept_ack(fd, char_id, 1);
  2303. +	return 1;
  2304.  }
  2305.  
  2306. -
  2307. -static void char_delete2_cancel(int fd, struct char_session_data* sd)
  2308. -{// CH: <082b>.W <char id>.L
  2309. +// CH: <082b>.W <char id>.L
  2310. +int char_parse_delete2_cancel(int fd, struct char_session_data* sd)
  2311. +{
  2312.  	int char_id, i;
  2313.  
  2314. +	FIFOSD_CHECK(6)
  2315. +
  2316.  	char_id = RFIFOL(fd,2);
  2317. +	RFIFOSKIP(fd,6);
  2318.  
  2319.  	ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
  2320.  	if( i == MAX_CHARS )
  2321.  	{// character not found
  2322.  		char_delete2_cancel_ack(fd, char_id, 2);
  2323. -		return;
  2324. +		return 0;
  2325.  	}
  2326.  
  2327.  	// there is no need to check, whether or not the character was
  2328. @@ -3777,637 +3482,52 @@
  2329.  	{
  2330.  		Sql_ShowDebug(sql_handle);
  2331.  		char_delete2_cancel_ack(fd, char_id, 2);
  2332. -		return;
  2333. +		return 0;
  2334.  	}
  2335.  
  2336.  	char_delete2_cancel_ack(fd, char_id, 1);
  2337. +	return 1;
  2338.  }
  2339.  
  2340. +int char_parse_maplogin(int fd){
  2341. +	int i;
  2342.  
  2343. -int parse_char(int fd)
  2344. -{
  2345. -	int i, ch;
  2346. -	char email[40];
  2347. -	unsigned short cmd;
  2348. -	int map_fd;
  2349. -	struct char_session_data* sd;
  2350. -	uint32 ipl = session[fd]->client_addr;
  2351. -
  2352. -	sd = (struct char_session_data*)session[fd]->session_data;
  2353. -
  2354. -	// disconnect any player if no login-server.
  2355. -	if(login_fd < 0)
  2356. -		set_eof(fd);
  2357. -
  2358. -	if(session[fd]->flag.eof)
  2359. -	{
  2360. -		if( sd != NULL && sd->auth )
  2361. -		{	// already authed client
  2362. -			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
  2363. -			if( data != NULL && data->fd == fd)
  2364. -				data->fd = -1;
  2365. -			if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
  2366. -				set_char_offline(-1,sd->account_id);
  2367. -		}
  2368. -		do_close(fd);
  2369. +	if (RFIFOREST(fd) < 60)
  2370.  		return 0;
  2371. -	}
  2372. -
  2373. -	while( RFIFOREST(fd) >= 2 )
  2374. -	{
  2375. -		//For use in packets that depend on an sd being present [Skotlex]
  2376. -		#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
  2377. -
  2378. -		cmd = RFIFOW(fd,0);
  2379. -		switch( cmd )
  2380. +	else {
  2381. +		char* l_user = (char*)RFIFOP(fd,2);
  2382. +		char* l_pass = (char*)RFIFOP(fd,26);
  2383. +		l_user[23] = '\0';
  2384. +		l_pass[23] = '\0';
  2385. +		ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
  2386. +		if( runflag != CHARSERVER_ST_RUNNING ||
  2387. +			i == ARRAYLENGTH(server) ||
  2388. +			strcmp(l_user, userid) != 0 ||
  2389. +			strcmp(l_pass, passwd) != 0 )
  2390.  		{
  2391. +			WFIFOHEAD(fd,3);
  2392. +			WFIFOW(fd,0) = 0x2af9;
  2393. +			WFIFOB(fd,2) = 3;
  2394. +			WFIFOSET(fd,3);
  2395. +		} else {
  2396. +			WFIFOHEAD(fd,3);
  2397. +			WFIFOW(fd,0) = 0x2af9;
  2398. +			WFIFOB(fd,2) = 0;
  2399. +			WFIFOSET(fd,3);
  2400.  
  2401. -		// request to connect
  2402. -		// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  2403. -		case 0x65:
  2404. -			if( RFIFOREST(fd) < 17 )
  2405. -				return 0;
  2406. -		{
  2407. -			struct auth_node* node;
  2408. -
  2409. -			int account_id = RFIFOL(fd,2);
  2410. -			uint32 login_id1 = RFIFOL(fd,6);
  2411. -			uint32 login_id2 = RFIFOL(fd,10);
  2412. -			int sex = RFIFOB(fd,16);
  2413. -			RFIFOSKIP(fd,17);
  2414. -
  2415. -			ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  2416. -
  2417. -			if (sd) {
  2418. -				//Received again auth packet for already authentified account?? Discard it.
  2419. -				//TODO: Perhaps log this as a hack attempt?
  2420. -				//TODO: and perhaps send back a reply?
  2421. -				break;
  2422. -			}
  2423. -
  2424. -			CREATE(session[fd]->session_data, struct char_session_data, 1);
  2425. -			sd = (struct char_session_data*)session[fd]->session_data;
  2426. -			sd->account_id = account_id;
  2427. -			sd->login_id1 = login_id1;
  2428. -			sd->login_id2 = login_id2;
  2429. -			sd->sex = sex;
  2430. -			sd->auth = false; // not authed yet
  2431. -
  2432. -			// send back account_id
  2433. -			WFIFOHEAD(fd,4);
  2434. -			WFIFOL(fd,0) = account_id;
  2435. -			WFIFOSET(fd,4);
  2436. -
  2437. -			if( runflag != CHARSERVER_ST_RUNNING )
  2438. -			{
  2439. -				WFIFOHEAD(fd,3);
  2440. -				WFIFOW(fd,0) = 0x6c;
  2441. -				WFIFOB(fd,2) = 0;// rejected from server
  2442. -				WFIFOSET(fd,3);
  2443. -				break;
  2444. -			}
  2445. -
  2446. -			// search authentification
  2447. -			node = (struct auth_node*)idb_get(auth_db, account_id);
  2448. -			if( node != NULL &&
  2449. -			    node->account_id == account_id &&
  2450. -				node->login_id1  == login_id1 &&
  2451. -				node->login_id2  == login_id2 /*&&
  2452. -				node->ip         == ipl*/ )
  2453. -			{// authentication found (coming from map server)
  2454. -				idb_remove(auth_db, account_id);
  2455. -				char_auth_ok(fd, sd);
  2456. -			}
  2457. -			else
  2458. -			{// authentication not found (coming from login server)
  2459. -				if (login_fd > 0) { // don't send request if no login-server
  2460. -					WFIFOHEAD(login_fd,23);
  2461. -					WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  2462. -					WFIFOL(login_fd,2) = sd->account_id;
  2463. -					WFIFOL(login_fd,6) = sd->login_id1;
  2464. -					WFIFOL(login_fd,10) = sd->login_id2;
  2465. -					WFIFOB(login_fd,14) = sd->sex;
  2466. -					WFIFOL(login_fd,15) = htonl(ipl);
  2467. -					WFIFOL(login_fd,19) = fd;
  2468. -					WFIFOSET(login_fd,23);
  2469. -				} else { // if no login-server, we must refuse connection
  2470. -					WFIFOHEAD(fd,3);
  2471. -					WFIFOW(fd,0) = 0x6c;
  2472. -					WFIFOB(fd,2) = 0;
  2473. -					WFIFOSET(fd,3);
  2474. -				}
  2475. -			}
  2476. +			server[i].fd = fd;
  2477. +			server[i].ip = ntohl(RFIFOL(fd,54));
  2478. +			server[i].port = ntohs(RFIFOW(fd,58));
  2479. +			server[i].users = 0;
  2480. +			memset(server[i].map, 0, sizeof(server[i].map));
  2481. +			session[fd]->func_parse = parse_frommap;
  2482. +			session[fd]->flag.server = 1;
  2483. +			realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  2484. +			char_mapif_init(fd);
  2485.  		}
  2486. -		break;
  2487. -
  2488. -		// char select
  2489. -		case 0x66:
  2490. -			FIFOSD_CHECK(3);
  2491. -		{
  2492. -			struct mmo_charstatus char_dat;
  2493. -			struct mmo_charstatus *cd;
  2494. -			char* data;
  2495. -			int char_id;
  2496. -			uint32 subnet_map_ip;
  2497. -			struct auth_node* node;
  2498. -
  2499. -			int slot = RFIFOB(fd,2);
  2500. -			RFIFOSKIP(fd,3);
  2501. -
  2502. -			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)
  2503. -			  || SQL_SUCCESS != Sql_NextRow(sql_handle)
  2504. -			  || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
  2505. -			{	//Not found?? May be forged packet.
  2506. -				Sql_ShowDebug(sql_handle);
  2507. -				Sql_FreeResult(sql_handle);
  2508. -				WFIFOHEAD(fd,3);
  2509. -				WFIFOW(fd,0) = 0x6c;
  2510. -				WFIFOB(fd,2) = 0; // rejected from server
  2511. -				WFIFOSET(fd,3);
  2512. -				break;
  2513. -			}
  2514. -
  2515. -			char_id = atoi(data);
  2516. -			Sql_FreeResult(sql_handle);
  2517. -
  2518. -			/* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  2519. -			set_char_online(-2,char_id,sd->account_id);
  2520. -			if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  2521. -				set_char_offline(char_id, sd->account_id);
  2522. -				/* failed to load something. REJECT! */
  2523. -				WFIFOHEAD(fd,3);
  2524. -				WFIFOW(fd,0) = 0x6c;
  2525. -				WFIFOB(fd,2) = 0;
  2526. -				WFIFOSET(fd,3);
  2527. -				break;/* jump off this boat */
  2528. -			}
  2529. -
  2530. -			//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  2531. -			cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
  2532. -			cd->sex = sd->sex;
  2533. -
  2534. -			if (log_char) {
  2535. -				char esc_name[NAME_LENGTH*2+1];
  2536. -
  2537. -				Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  2538. -				if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  2539. -					charlog_db, sd->account_id, slot, esc_name) )
  2540. -					Sql_ShowDebug(sql_handle);
  2541. -			}
  2542. -			ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  2543. -
  2544. -			// searching map server
  2545. -			i = search_mapserver(cd->last_point.map, -1, -1);
  2546. -
  2547. -			// if map is not found, we check major cities
  2548. -			if (i < 0 || !cd->last_point.map) {
  2549. -				unsigned short j;
  2550. -				//First check that there's actually a map server online.
  2551. -				ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
  2552. -				if (j == ARRAYLENGTH(server)) {
  2553. -					ShowInfo("Connection Closed. No map servers available.\n");
  2554. -					WFIFOHEAD(fd,3);
  2555. -					WFIFOW(fd,0) = 0x81;
  2556. -					WFIFOB(fd,2) = 1; // 01 = Server closed
  2557. -					WFIFOSET(fd,3);
  2558. -					break;
  2559. -				}
  2560. -				if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  2561. -					cd->last_point.x = 273;
  2562. -					cd->last_point.y = 354;
  2563. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  2564. -					cd->last_point.x = 120;
  2565. -					cd->last_point.y = 100;
  2566. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  2567. -					cd->last_point.x = 160;
  2568. -					cd->last_point.y = 94;
  2569. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  2570. -					cd->last_point.x = 116;
  2571. -					cd->last_point.y = 57;
  2572. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  2573. -					cd->last_point.x = 87;
  2574. -					cd->last_point.y = 117;
  2575. -				} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  2576. -					cd->last_point.x = 94;
  2577. -					cd->last_point.y = 103;
  2578. -				} else {
  2579. -					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));
  2580. -					WFIFOHEAD(fd,3);
  2581. -					WFIFOW(fd,0) = 0x81;
  2582. -					WFIFOB(fd,2) = 1; // 01 = Server closed
  2583. -					WFIFOSET(fd,3);
  2584. -					break;
  2585. -				}
  2586. -				ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  2587. -				cd->last_point.map = j;
  2588. -			}
  2589. -
  2590. -			//Send NEW auth packet [Kevin]
  2591. -			//FIXME: is this case even possible? [ultramage]
  2592. -			if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
  2593. -			{
  2594. -				ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  2595. -				server[i].fd = -1;
  2596. -				memset(&server[i], 0, sizeof(struct mmo_map_server));
  2597. -				//Send server closed.
  2598. -				WFIFOHEAD(fd,3);
  2599. -				WFIFOW(fd,0) = 0x81;
  2600. -				WFIFOB(fd,2) = 1; // 01 = Server closed
  2601. -				WFIFOSET(fd,3);
  2602. -				break;
  2603. -			}
  2604. -
  2605. -			//Send player to map
  2606. -			WFIFOHEAD(fd,28);
  2607. -			WFIFOW(fd,0) = 0x71;
  2608. -			WFIFOL(fd,2) = cd->char_id;
  2609. -			mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
  2610. -			subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  2611. -			WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
  2612. -			WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  2613. -			WFIFOSET(fd,28);
  2614. -
  2615. -			// create temporary auth entry
  2616. -			CREATE(node, struct auth_node, 1);
  2617. -			node->account_id = sd->account_id;
  2618. -			node->char_id = cd->char_id;
  2619. -			node->login_id1 = sd->login_id1;
  2620. -			node->login_id2 = sd->login_id2;
  2621. -			node->sex = sd->sex;
  2622. -			node->expiration_time = sd->expiration_time;
  2623. -			node->group_id = sd->group_id;
  2624. -			node->ip = ipl;
  2625. -			idb_put(auth_db, sd->account_id, node);
  2626. -
  2627. -		}
  2628. -		break;
  2629. -
  2630. -		// create new char
  2631. -#if PACKETVER >= 20120307
  2632. -		// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  2633. -		case 0x970:
  2634. -			FIFOSD_CHECK(31);
  2635. -#else
  2636. -		// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  2637. -		case 0x67:
  2638. -			FIFOSD_CHECK(37);
  2639. -#endif
  2640. -
  2641. -			if( !char_new ) //turn character creation on/off [Kevin]
  2642. -				i = -2;
  2643. -			else
  2644. -#if PACKETVER >= 20120307
  2645. -				i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
  2646. -#else
  2647. -				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));
  2648. -#endif
  2649. -
  2650. -			//'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
  2651. -			if (i < 0) {
  2652. -				WFIFOHEAD(fd,3);
  2653. -				WFIFOW(fd,0) = 0x6e;
  2654. -				/* Others I found [Ind] */
  2655. -				/* 0x02 = Symbols in Character Names are forbidden */
  2656. -				/* 0x03 = You are not elegible to open the Character Slot. */
  2657. -				switch (i) {
  2658. -					case -1: WFIFOB(fd,2) = 0x00; break;
  2659. -					case -2: WFIFOB(fd,2) = 0xFF; break;
  2660. -					case -3: WFIFOB(fd,2) = 0x01; break;
  2661. -					case -4: WFIFOB(fd,2) = 0x03; break;
  2662. -				}
  2663. -				WFIFOSET(fd,3);
  2664. -			} else {
  2665. -				int len;
  2666. -				// retrieve data
  2667. -				struct mmo_charstatus char_dat;
  2668. -				mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
  2669. -
  2670. -				// send to player
  2671. -				WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  2672. -				WFIFOW(fd,0) = 0x6d;
  2673. -				len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  2674. -				WFIFOSET(fd,len);
  2675. -
  2676. -				// add new entry to the chars list
  2677. -				ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
  2678. -				if( ch < MAX_CHARS )
  2679. -					sd->found_char[ch] = i; // the char_id of the new char
  2680. -			}
  2681. -#if PACKETVER >= 20120307
  2682. -			RFIFOSKIP(fd,31);
  2683. -#else
  2684. -			RFIFOSKIP(fd,37);
  2685. -#endif
  2686. -		break;
  2687. -
  2688. -		// delete char
  2689. -		case 0x68:
  2690. -		// 2004-04-19aSakexe+ langtype 12 char deletion packet
  2691. -		case 0x1fb:
  2692. -			if (cmd == 0x68) FIFOSD_CHECK(46);
  2693. -			if (cmd == 0x1fb) FIFOSD_CHECK(56);
  2694. -		{
  2695. -			int cid = RFIFOL(fd,2);
  2696. -
  2697. -			ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
  2698. -			memcpy(email, RFIFOP(fd,6), 40);
  2699. -			RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  2700. -
  2701. -			// Check if e-mail is correct
  2702. -			if(strcmpi(email, sd->email) && //email does not matches and
  2703. -			(
  2704. -				strcmp("a@a.com", sd->email) || //it is not default email, or
  2705. -				(strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default
  2706. -			)) {	//Fail
  2707. -				WFIFOHEAD(fd,3);
  2708. -				WFIFOW(fd,0) = 0x70;
  2709. -				WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
  2710. -				WFIFOSET(fd,3);
  2711. -				break;
  2712. -			}
  2713. -
  2714. -			// check if this char exists
  2715. -			ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  2716. -			if( i == MAX_CHARS )
  2717. -			{ // Such a character does not exist in the account
  2718. -				WFIFOHEAD(fd,3);
  2719. -				WFIFOW(fd,0) = 0x70;
  2720. -				WFIFOB(fd,2) = 0;
  2721. -				WFIFOSET(fd,3);
  2722. -				break;
  2723. -			}
  2724. -
  2725. -			// remove char from list and compact it
  2726. -			for(ch = i; ch < MAX_CHARS-1; ch++)
  2727. -				sd->found_char[ch] = sd->found_char[ch+1];
  2728. -			sd->found_char[MAX_CHARS-1] = -1;
  2729. -
  2730. -			/* Delete character */
  2731. -			if(delete_char_sql(cid)<0){
  2732. -				//can't delete the char
  2733. -				//either SQL error or can't delete by some CONFIG conditions
  2734. -				//del fail
  2735. -				WFIFOHEAD(fd,3);
  2736. -				WFIFOW(fd, 0) = 0x70;
  2737. -				WFIFOB(fd, 2) = 0;
  2738. -				WFIFOSET(fd, 3);
  2739. -				break;
  2740. -			}
  2741. -			/* Char successfully deleted.*/
  2742. -			WFIFOHEAD(fd,2);
  2743. -			WFIFOW(fd,0) = 0x6f;
  2744. -			WFIFOSET(fd,2);
  2745. -		}
  2746. -		break;
  2747. -
  2748. -		// client keep-alive packet (every 12 seconds)
  2749. -		// R 0187 <account ID>.l
  2750. -		case 0x187:
  2751. -			if (RFIFOREST(fd) < 6)
  2752. -				return 0;
  2753. -			RFIFOSKIP(fd,6);
  2754. -		break;
  2755. -		// char rename request
  2756. -		// R 08fc <char ID>.l <new name>.24B
  2757. -		case 0x8fc:
  2758. -			FIFOSD_CHECK(30);
  2759. -			{
  2760. -				int i, cid =RFIFOL(fd,2);
  2761. -				char name[NAME_LENGTH];
  2762. -				char esc_name[NAME_LENGTH*2+1];
  2763. -				safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH);
  2764. -				RFIFOSKIP(fd,30);
  2765. -
  2766. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  2767. -				if( i == MAX_CHARS )
  2768. -					break;
  2769. -
  2770. -				normalize_name(name,TRIM_CHARS);
  2771. -				Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  2772. -				if( !check_char_name(name,esc_name) ) {
  2773. -					i = 1;
  2774. -					safestrncpy(sd->new_name, name, NAME_LENGTH);
  2775. -				} else
  2776. -					i = 0;
  2777. -
  2778. -				WFIFOHEAD(fd, 4);
  2779. -				WFIFOW(fd,0) = 0x28e;
  2780. -				WFIFOW(fd,2) = i;
  2781. -				WFIFOSET(fd,4);
  2782. -			}
  2783. -			break;
  2784. -
  2785. -		// char rename request
  2786. -		// R 028d <account ID>.l <char ID>.l <new name>.24B
  2787. -		case 0x28d:
  2788. -			FIFOSD_CHECK(34);
  2789. -			{
  2790. -				int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6);
  2791. -				char name[NAME_LENGTH];
  2792. - 				char esc_name[NAME_LENGTH*2+1];
  2793. -				safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
  2794. -				RFIFOSKIP(fd,34);
  2795. -
  2796. -				if( aid != sd->account_id )
  2797. -					break;
  2798. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  2799. -				if( i == MAX_CHARS )
  2800. -					break;
  2801. -
  2802. -				normalize_name(name,TRIM_CHARS);
  2803. -				Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  2804. -				if( !check_char_name(name,esc_name) )
  2805. -				{
  2806. -					i = 1;
  2807. -					safestrncpy(sd->new_name, name, NAME_LENGTH);
  2808. -				}
  2809. -				else
  2810. -					i = 0;
  2811. -
  2812. -				WFIFOHEAD(fd, 4);
  2813. -				WFIFOW(fd,0) = 0x28e;
  2814. -				WFIFOW(fd,2) = i;
  2815. -				WFIFOSET(fd,4);
  2816. -			}
  2817. -			break;
  2818. -		//Confirm change name.
  2819. -		// 0x28f <char_id>.L
  2820. -		case 0x28f:
  2821. -			// 0: Sucessfull
  2822. -			// 1: This character's name has already been changed. You cannot change a character's name more than once.
  2823. -			// 2: User information is not correct.
  2824. -			// 3: You have failed to change this character's name.
  2825. -			// 4: Another user is using this character name, so please select another one.
  2826. -			FIFOSD_CHECK(6);
  2827. -			{
  2828. -				int i;
  2829. -				int cid = RFIFOL(fd,2);
  2830. -				RFIFOSKIP(fd,6);
  2831. -
  2832. -				ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  2833. -				if( i == MAX_CHARS )
  2834. -					break;
  2835. -				i = rename_char_sql(sd, cid);
  2836. -
  2837. -				WFIFOHEAD(fd, 4);
  2838. -				WFIFOW(fd,0) = 0x290;
  2839. -				WFIFOW(fd,2) = i;
  2840. -				WFIFOSET(fd,4);
  2841. -			}
  2842. -			break;
  2843. -
  2844. -		// captcha code request (not implemented)
  2845. -		// R 07e5 <?>.w <aid>.l
  2846. -		case 0x7e5:
  2847. -			WFIFOHEAD(fd,5);
  2848. -			WFIFOW(fd,0) = 0x7e9;
  2849. -			WFIFOW(fd,2) = 5;
  2850. -			WFIFOB(fd,4) = 1;
  2851. -			WFIFOSET(fd,5);
  2852. -			RFIFOSKIP(fd,8);
  2853. -			break;
  2854. -
  2855. -		// captcha code check (not implemented)
  2856. -		// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  2857. -		case 0x7e7:
  2858. -			WFIFOHEAD(fd,5);
  2859. -			WFIFOW(fd,0) = 0x7e9;
  2860. -			WFIFOW(fd,2) = 5;
  2861. -			WFIFOB(fd,4) = 1;
  2862. -			WFIFOSET(fd,5);
  2863. -			RFIFOSKIP(fd,32);
  2864. -		break;
  2865. -
  2866. -		// deletion timer request
  2867. -		case 0x827:
  2868. -			FIFOSD_CHECK(6);
  2869. -			char_delete2_req(fd, sd);
  2870. -			RFIFOSKIP(fd,6);
  2871. -		break;
  2872. -
  2873. -		// deletion accept request
  2874. -		case 0x829:
  2875. -			FIFOSD_CHECK(12);
  2876. -			char_delete2_accept(fd, sd);
  2877. -			RFIFOSKIP(fd,12);
  2878. -		break;
  2879. -
  2880. -		// deletion cancel request
  2881. -		case 0x82b:
  2882. -			FIFOSD_CHECK(6);
  2883. -			char_delete2_cancel(fd, sd);
  2884. -			RFIFOSKIP(fd,6);
  2885. -		break;
  2886. -
  2887. -		// login as map-server
  2888. -		case 0x2af8:
  2889. -			if (RFIFOREST(fd) < 60)
  2890. -				return 0;
  2891. -			else {
  2892. -				char* l_user = (char*)RFIFOP(fd,2);
  2893. -				char* l_pass = (char*)RFIFOP(fd,26);
  2894. -				l_user[23] = '\0';
  2895. -				l_pass[23] = '\0';
  2896. -				ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
  2897. -				if( runflag != CHARSERVER_ST_RUNNING ||
  2898. -					i == ARRAYLENGTH(server) ||
  2899. -					strcmp(l_user, userid) != 0 ||
  2900. -					strcmp(l_pass, passwd) != 0 )
  2901. -				{
  2902. -					WFIFOHEAD(fd,3);
  2903. -					WFIFOW(fd,0) = 0x2af9;
  2904. -					WFIFOB(fd,2) = 3;
  2905. -					WFIFOSET(fd,3);
  2906. -				} else {
  2907. -					WFIFOHEAD(fd,3);
  2908. -					WFIFOW(fd,0) = 0x2af9;
  2909. -					WFIFOB(fd,2) = 0;
  2910. -					WFIFOSET(fd,3);
  2911. -
  2912. -					server[i].fd = fd;
  2913. -					server[i].ip = ntohl(RFIFOL(fd,54));
  2914. -					server[i].port = ntohs(RFIFOW(fd,58));
  2915. -					server[i].users = 0;
  2916. -					memset(server[i].map, 0, sizeof(server[i].map));
  2917. -					session[fd]->func_parse = parse_frommap;
  2918. -					session[fd]->flag.server = 1;
  2919. -					realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  2920. -					char_mapif_init(fd);
  2921. -				}
  2922. -				RFIFOSKIP(fd,60);
  2923. -			}
  2924. -			return 0; // avoid processing of followup packets here
  2925. -
  2926. -		// checks the entered pin
  2927. -		case 0x8b8:
  2928. -			if( RFIFOREST(fd) < 10 )
  2929. -				return 0;
  2930. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  2931. -				pincode_check( fd, sd );
  2932. -			RFIFOSKIP(fd,10);
  2933. -		break;
  2934. -
  2935. -		// request for PIN window
  2936. -		case 0x8c5:
  2937. -			if( RFIFOREST(fd) < 6 )
  2938. -				return 0;
  2939. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  2940. -				if( strlen( sd->pincode ) <= 0 ){
  2941. -					pincode_sendstate( fd, sd, PINCODE_NEW );
  2942. -				}else{
  2943. -					pincode_sendstate( fd, sd, PINCODE_ASK );
  2944. -				}
  2945. -			}
  2946. -			RFIFOSKIP(fd,6);
  2947. -		break;
  2948. -
  2949. -		// pincode change request
  2950. -		case 0x8be:
  2951. -			if( RFIFOREST(fd) < 14 )
  2952. -				return 0;
  2953. -
  2954. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  2955. -				pincode_change( fd, sd );
  2956. -
  2957. -			RFIFOSKIP(fd,14);
  2958. -		break;
  2959. -
  2960. -		// activate PIN system and set first PIN
  2961. -		case 0x8ba:
  2962. -			if( RFIFOREST(fd) < 10 )
  2963. -				return 0;
  2964. -			if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
  2965. -				pincode_setnew( fd, sd );
  2966. -			RFIFOSKIP(fd,10);
  2967. -		break;
  2968. -
  2969. -		// character movement request
  2970. -		case 0x8d4:
  2971. -			if( RFIFOREST(fd) < 8 )
  2972. -				return 0;
  2973. -
  2974. -			moveCharSlot( fd, sd, RFIFOW(fd, 2), RFIFOW(fd, 4) );
  2975. -			mmo_char_send(fd, sd);
  2976. -			RFIFOSKIP(fd,8);
  2977. -		break;
  2978. -
  2979. -		case 0x9a1:
  2980. -			if( RFIFOREST(fd) < 2 )
  2981. -				return 0;
  2982. -			char_parse_req_charlist(fd,sd);
  2983. -			RFIFOSKIP(fd,2);
  2984. -			break;
  2985. -
  2986. -		// unknown packet received
  2987. -		default:
  2988. -			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));
  2989. -			set_eof(fd);
  2990. -			return 0;
  2991. -		}
  2992. +		RFIFOSKIP(fd,60);
  2993.  	}
  2994. -
  2995. -	RFIFOFLUSH(fd);
  2996. -	return 0;
  2997. +	return 1;
  2998.  }
  2999.  
  3000.  // Console Command Parser [Wizputer]
  3001. @@ -4563,53 +3683,84 @@
  3002.  	return 0;
  3003.  }
  3004.  
  3005. -int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
  3006. -{
  3007. -	if (login_fd > 0 && session[login_fd] != NULL)
  3008. -		return 0;
  3009. +//------------------------------------------------
  3010. +//Pincode system
  3011. +//------------------------------------------------
  3012.  
  3013. -	ShowInfo("Attempt to connect to login-server...\n");
  3014. -	login_fd = make_connection(login_ip, login_port, false,10);
  3015. -	if (login_fd == -1)
  3016. -	{	//Try again later. [Skotlex]
  3017. -		login_fd = 0;
  3018. +/* pincode_sendstate transmist the pincode state to client
  3019. + * S 08b9 <seed>.L <aid>.L <state>.W (HC_SECOND_PASSWD_LOGIN)
  3020. + * state :
  3021. + *   0 = disabled / pin is correct
  3022. + *   1 = ask for pin - client sends 0x8b8
  3023. + *   2 = create new pin - client sends 0x8ba
  3024. + *   3 = pin must be changed - client 0x8be
  3025. + *   4 = create new pin - client sends 0x8ba
  3026. + *   5 = client shows msgstr(1896)
  3027. + *   6 = client shows msgstr(1897) Unable to use your KSSN number
  3028. + *   7 = char select window shows a button - client sends 0x8c5
  3029. + *   8 = pincode was incorrect
  3030. +*/
  3031. +void pincode_sendstate( int fd, struct char_session_data* sd, enum pincode_state state ){
  3032. +	WFIFOHEAD(fd, 12);
  3033. +	WFIFOW(fd, 0) = 0x8b9;
  3034. +	WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  3035. +	WFIFOL(fd, 6) = sd->account_id;
  3036. +	WFIFOW(fd,10) = state;
  3037. +	WFIFOSET(fd,12);
  3038. +}
  3039. +
  3040. +void pincode_notifyLoginPinError( int account_id ){
  3041. +	WFIFOHEAD(login_fd,6);
  3042. +	WFIFOW(login_fd,0) = 0x2739;
  3043. +	WFIFOL(login_fd,2) = account_id;
  3044. +	WFIFOSET(login_fd,6);
  3045. +}
  3046. +
  3047. +void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
  3048. +	WFIFOHEAD(login_fd,11);
  3049. +	WFIFOW(login_fd,0) = 0x2738;
  3050. +	WFIFOL(login_fd,2) = account_id;
  3051. +	strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
  3052. +	WFIFOSET(login_fd,11);
  3053. +}
  3054. +
  3055. +int char_parse_reqpincode_window(int fd, struct char_session_data* sd){
  3056. +	if( RFIFOREST(fd) < 6 )
  3057.  		return 0;
  3058. +	if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
  3059. +		if( strlen( sd->pincode ) <= 0 ){
  3060. +			pincode_sendstate( fd, sd, PINCODE_NEW );
  3061. +		}else{
  3062. +			pincode_sendstate( fd, sd, PINCODE_ASK );
  3063. +		}
  3064.  	}
  3065. -	session[login_fd]->func_parse = parse_fromlogin;
  3066. -	session[login_fd]->flag.server = 1;
  3067. -	realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  3068. -
  3069. -	WFIFOHEAD(login_fd,86);
  3070. -	WFIFOW(login_fd,0) = 0x2710;
  3071. -	memcpy(WFIFOP(login_fd,2), userid, 24);
  3072. -	memcpy(WFIFOP(login_fd,26), passwd, 24);
  3073. -	WFIFOL(login_fd,50) = 0;
  3074. -	WFIFOL(login_fd,54) = htonl(char_ip);
  3075. -	WFIFOW(login_fd,58) = htons(char_port);
  3076. -	memcpy(WFIFOP(login_fd,60), server_name, 20);
  3077. -	WFIFOW(login_fd,80) = 0;
  3078. -	WFIFOW(login_fd,82) = char_maintenance;
  3079. -	WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
  3080. -	WFIFOSET(login_fd,86);
  3081. -
  3082. +	RFIFOSKIP(fd,6);
  3083.  	return 1;
  3084.  }
  3085.  
  3086. -//------------------------------------------------
  3087. -//Pincode system
  3088. -//------------------------------------------------
  3089. -void pincode_check( int fd, struct char_session_data* sd ){
  3090. -	char pin[PINCODE_LENGTH+1];
  3091. +void pincode_decrypt( uint32 userSeed, char* pin ){
  3092. +	int i, pos;
  3093. +	char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  3094. +	char *buf;
  3095. +	uint32 multiplier = 0x3498, baseSeed = 0x881234;
  3096.  
  3097. -	memset(pin,0,PINCODE_LENGTH+1);
  3098. +	for( i = 1; i < 10; i++ ){
  3099. +		userSeed = baseSeed + userSeed * multiplier;
  3100. +		pos = userSeed % ( i + 1 );
  3101. +		if( i != pos ){
  3102. +			tab[i] ^= tab[pos];
  3103. +			tab[pos] ^= tab[i];
  3104. +			tab[i] ^= tab[pos];
  3105. +		}
  3106. +	}
  3107.  
  3108. -	strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
  3109. -
  3110. -	pincode_decrypt(sd->pincode_seed, pin );
  3111. -
  3112. -	if( pincode_compare( fd, sd, pin ) ){
  3113. -		pincode_sendstate( fd, sd, PINCODE_PASSED );
  3114. +	buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
  3115. +	memset( buf, 0, PINCODE_LENGTH + 1 );
  3116. +	for( i = 0; i < PINCODE_LENGTH; i++ ){
  3117. +		sprintf( buf + i, "%d", tab[pin[i] - '0'] );
  3118.  	}
  3119. +	strcpy( pin, buf );
  3120. +	free( buf );
  3121.  }
  3122.  
  3123.  int pincode_compare( int fd, struct char_session_data* sd, char* pin ){
  3124. @@ -4627,114 +3778,110 @@
  3125.  	}
  3126.  }
  3127.  
  3128. -void pincode_change( int fd, struct char_session_data* sd ){
  3129. +int char_parse_pincode_check( int fd, struct char_session_data* sd ){
  3130. +	char pin[PINCODE_LENGTH+1];
  3131. +
  3132. +	if( RFIFOREST(fd) < 10 )
  3133. +		return 0;
  3134. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  3135. +		return 0;
  3136. +
  3137. +	memset(pin,0,PINCODE_LENGTH+1);
  3138. +	strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
  3139. +	RFIFOSKIP(fd,10);
  3140. +
  3141. +	pincode_decrypt(sd->pincode_seed, pin );
  3142. +	if( pincode_compare( fd, sd, pin ) ){
  3143. +		pincode_sendstate( fd, sd, PINCODE_PASSED );
  3144. +	}
  3145. +	return 1;
  3146. +}
  3147. +
  3148. +int char_parse_pincode_change( int fd, struct char_session_data* sd ){
  3149.  	char oldpin[PINCODE_LENGTH+1];
  3150.  	char newpin[PINCODE_LENGTH+1];
  3151.  
  3152. +	if( RFIFOREST(fd) < 14 )
  3153. +		return 0;
  3154. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  3155. +		return 0;
  3156. +
  3157.  	memset(oldpin,0,PINCODE_LENGTH+1);
  3158.  	memset(newpin,0,PINCODE_LENGTH+1);
  3159. +	strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
  3160. +	strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
  3161. +	RFIFOSKIP(fd,14);
  3162.  
  3163. -	strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
  3164.  	pincode_decrypt(sd->pincode_seed,oldpin);
  3165. -
  3166.  	if( !pincode_compare( fd, sd, oldpin ) )
  3167. -		return;
  3168. -
  3169. -	strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
  3170. +		return 0;
  3171.  	pincode_decrypt(sd->pincode_seed,newpin);
  3172.  
  3173.  	pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  3174.  	strncpy(sd->pincode, newpin, sizeof(newpin));
  3175.  
  3176.  	pincode_sendstate( fd, sd, PINCODE_PASSED );
  3177. +	return 1;
  3178.  }
  3179.  
  3180. -void pincode_setnew( int fd, struct char_session_data* sd ){
  3181. +int char_parse_pincode_setnew( int fd, struct char_session_data* sd ){
  3182.  	char newpin[PINCODE_LENGTH+1];
  3183.  
  3184.  	memset(newpin,0,PINCODE_LENGTH+1);
  3185.  
  3186. +	if( RFIFOREST(fd) < 10 )
  3187. +		return 0;
  3188. +
  3189. +	if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
  3190. +		return 0;
  3191.  	strncpy( newpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH );
  3192. +	RFIFOSKIP(fd,10);
  3193. +
  3194.  	pincode_decrypt( sd->pincode_seed, newpin );
  3195.  
  3196.  	pincode_notifyLoginPinUpdate( sd->account_id, newpin );
  3197.  	strncpy( sd->pincode, newpin, strlen( newpin ) );
  3198.  
  3199.  	pincode_sendstate( fd, sd, PINCODE_PASSED );
  3200. +	return 1;
  3201.  }
  3202.  
  3203. -// 0 = disabled / pin is correct
  3204. -// 1 = ask for pin - client sends 0x8b8
  3205. -// 2 = create new pin - client sends 0x8ba
  3206. -// 3 = pin must be changed - client 0x8be
  3207. -// 4 = create new pin - client sends 0x8ba
  3208. -// 5 = client shows msgstr(1896)
  3209. -// 6 = client shows msgstr(1897) Unable to use your KSSN number
  3210. -// 7 = char select window shows a button - client sends 0x8c5
  3211. -// 8 = pincode was incorrect
  3212. -void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state ){
  3213. -	WFIFOHEAD(fd, 12);
  3214. -	WFIFOW(fd, 0) = 0x8b9;
  3215. -	WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
  3216. -	WFIFOL(fd, 6) = sd->account_id;
  3217. -	WFIFOW(fd,10) = state;
  3218. -	WFIFOSET(fd,12);
  3219. -}
  3220.  
  3221. -void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
  3222. -	WFIFOHEAD(login_fd,11);
  3223. -	WFIFOW(login_fd,0) = 0x2738;
  3224. -	WFIFOL(login_fd,2) = account_id;
  3225. -	strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
  3226. -	WFIFOSET(login_fd,11);
  3227. +//------------------------------------------------
  3228. +//Add On system
  3229. +//------------------------------------------------
  3230. +// reason
  3231. +// 0: success
  3232. +// 1: failed
  3233. +void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  3234. +	WFIFOHEAD(fd,8);
  3235. +	WFIFOW(fd,0) = 0x8d5;
  3236. +	WFIFOW(fd,2) = 8;
  3237. +	WFIFOW(fd,4) = reason;
  3238. +	WFIFOW(fd,6) = sd->char_moves[index];
  3239. +	WFIFOSET(fd,8);
  3240.  }
  3241.  
  3242. -void pincode_notifyLoginPinError( int account_id ){
  3243. -	WFIFOHEAD(login_fd,6);
  3244. -	WFIFOW(login_fd,0) = 0x2739;
  3245. -	WFIFOL(login_fd,2) = account_id;
  3246. -	WFIFOSET(login_fd,6);
  3247. -}
  3248. +int char_parse_moveCharSlot( int fd, struct char_session_data* sd){
  3249. +	uint16 from, to;
  3250.  
  3251. -void pincode_decrypt( uint32 userSeed, char* pin ){
  3252. -	int i, pos;
  3253. -	char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  3254. -	char *buf;
  3255. -	uint32 multiplier = 0x3498, baseSeed = 0x881234;
  3256. +	if( RFIFOREST(fd) < 8 )
  3257. +		return 0;
  3258. +	from = RFIFOW(fd,2);
  3259. +	to = RFIFOW(fd,4);
  3260. +	//Cnt = RFIFOW(fd,6); //how many time we have left to change (client.. lol we don't trust him)
  3261. +	RFIFOSKIP(fd,8);
  3262.  
  3263. -	for( i = 1; i < 10; i++ ){
  3264. -		userSeed = baseSeed + userSeed * multiplier;
  3265. -		pos = userSeed % ( i + 1 );
  3266. -		if( i != pos ){
  3267. -			tab[i] ^= tab[pos];
  3268. -			tab[pos] ^= tab[i];
  3269. -			tab[i] ^= tab[pos];
  3270. -		}
  3271. -	}
  3272. -
  3273. -	buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
  3274. -	memset( buf, 0, PINCODE_LENGTH + 1 );
  3275. -	for( i = 0; i < PINCODE_LENGTH; i++ ){
  3276. -		sprintf( buf + i, "%d", tab[pin[i] - '0'] );
  3277. -	}
  3278. -	strcpy( pin, buf );
  3279. -	free( buf );
  3280. -}
  3281. -
  3282. -//------------------------------------------------
  3283. -//Add On system
  3284. -//------------------------------------------------
  3285. -void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to ){
  3286.  	// Have we changed to often or is it disabled?
  3287.  	if( !char_move_enabled || ( !char_moves_unlimited && sd->char_moves[from] <= 0 ) ){
  3288.  		moveCharSlotReply( fd, sd, from, 1 );
  3289. -		return;
  3290. +		return 0;
  3291.  	}
  3292.  
  3293.  	// We dont even have a character on the chosen slot?
  3294.  	if( sd->found_char[from] <= 0 ){
  3295.  		moveCharSlotReply( fd, sd, from, 1 );
  3296. -		return;
  3297. +		return 0;
  3298.  	}
  3299.  
  3300.  	if( sd->found_char[to] > 0 ){
  3301. @@ -4749,17 +3896,17 @@
  3302.  				moveCharSlotReply( fd, sd, from, 1 );
  3303.  				Sql_ShowDebug(sql_handle);
  3304.  				Sql_QueryStr(sql_handle,"ROLLBACK");
  3305. -				return;
  3306. +				return 0;
  3307.  			}
  3308.  		}else{
  3309.  			// Admin doesnt allow us to
  3310.  			moveCharSlotReply( fd, sd, from, 1 );
  3311. -			return;
  3312. +			return 0;
  3313.  		}
  3314.  	}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] ) ){
  3315.  		Sql_ShowDebug(sql_handle);
  3316.  		moveCharSlotReply( fd, sd, from, 1 );
  3317. -		return;
  3318. +		return 0;
  3319.  	}
  3320.  
  3321.  	if( !char_moves_unlimited ){
  3322. @@ -4770,20 +3917,9 @@
  3323.  	// We successfully moved the char - time to notify the client
  3324.  	moveCharSlotReply( fd, sd, from, 0 );
  3325.  	mmo_char_send(fd, sd);
  3326. +	return 1;
  3327.  }
  3328.  
  3329. -// reason
  3330. -// 0: success
  3331. -// 1: failed
  3332. -void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
  3333. -	WFIFOHEAD(fd,8);
  3334. -	WFIFOW(fd,0) = 0x8d5;
  3335. -	WFIFOW(fd,2) = 8;
  3336. -	WFIFOW(fd,4) = reason;
  3337. -	WFIFOW(fd,6) = sd->char_moves[index];
  3338. -	WFIFOSET(fd,8);
  3339. -}
  3340. -
  3341.  //------------------------------------------------
  3342.  //Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
  3343.  //replies/disconnect the player we tried to kick. [Skotlex]
  3344. @@ -5154,6 +4290,986 @@
  3345.  	return 0;
  3346.  }
  3347.  
  3348. +
  3349. +
  3350. +// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
  3351. +int char_parse_reqtoconnect(int fd, struct char_session_data* sd,uint32 ipl){
  3352. +	if( RFIFOREST(fd) < 17 ) // request to connect
  3353. +		return 0;
  3354. +	else {
  3355. +		struct auth_node* node;
  3356. +
  3357. +		int account_id = RFIFOL(fd,2);
  3358. +		uint32 login_id1 = RFIFOL(fd,6);
  3359. +		uint32 login_id2 = RFIFOL(fd,10);
  3360. +		int sex = RFIFOB(fd,16);
  3361. +		RFIFOSKIP(fd,17);
  3362. +
  3363. +		ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
  3364. +
  3365. +		if (sd) {
  3366. +			//Received again auth packet for already authentified account?? Discard it.
  3367. +			//TODO: Perhaps log this as a hack attempt?
  3368. +			//TODO: and perhaps send back a reply?
  3369. +			ShowInfo("Already registered break\n");
  3370. +			return 0;
  3371. +		}
  3372. +
  3373. +		CREATE(session[fd]->session_data, struct char_session_data, 1);
  3374. +		sd = (struct char_session_data*)session[fd]->session_data;
  3375. +		sd->account_id = account_id;
  3376. +		sd->login_id1 = login_id1;
  3377. +		sd->login_id2 = login_id2;
  3378. +		sd->sex = sex;
  3379. +		sd->auth = false; // not authed yet
  3380. +
  3381. +		// send back account_id
  3382. +		WFIFOHEAD(fd,4);
  3383. +		WFIFOL(fd,0) = account_id;
  3384. +		WFIFOSET(fd,4);
  3385. +
  3386. +		if( runflag != CHARSERVER_ST_RUNNING )
  3387. +		{
  3388. +			WFIFOHEAD(fd,3);
  3389. +			WFIFOW(fd,0) = 0x6c;
  3390. +			WFIFOB(fd,2) = 0;// rejected from server
  3391. +			WFIFOSET(fd,3);
  3392. +			return 0;
  3393. +		}
  3394. +
  3395. +		// search authentification
  3396. +		node = (struct auth_node*)idb_get(auth_db, account_id);
  3397. +		if( node != NULL &&
  3398. +		    node->account_id == account_id &&
  3399. +			node->login_id1  == login_id1 &&
  3400. +			node->login_id2  == login_id2 /*&&
  3401. +			node->ip         == ipl*/ )
  3402. +		{// authentication found (coming from map server)
  3403. +			idb_remove(auth_db, account_id);
  3404. +			char_auth_ok(fd, sd);
  3405. +		}
  3406. +		else
  3407. +		{// authentication not found (coming from login server)
  3408. +			if (login_fd > 0) { // don't send request if no login-server
  3409. +				WFIFOHEAD(login_fd,23);
  3410. +				WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  3411. +				WFIFOL(login_fd,2) = sd->account_id;
  3412. +				WFIFOL(login_fd,6) = sd->login_id1;
  3413. +				WFIFOL(login_fd,10) = sd->login_id2;
  3414. +				WFIFOB(login_fd,14) = sd->sex;
  3415. +				WFIFOL(login_fd,15) = htonl(ipl);
  3416. +				WFIFOL(login_fd,19) = fd;
  3417. +				WFIFOSET(login_fd,23);
  3418. +			} else { // if no login-server, we must refuse connection
  3419. +				WFIFOHEAD(fd,3);
  3420. +				WFIFOW(fd,0) = 0x6c;
  3421. +				WFIFOB(fd,2) = 0;
  3422. +				WFIFOSET(fd,3);
  3423. +			}
  3424. +		}
  3425. +	}
  3426. +	return 1;
  3427. +}
  3428. +
  3429. +int char_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
  3430. +	FIFOSD_CHECK(3);
  3431. +	{
  3432. +		struct mmo_charstatus char_dat;
  3433. +		struct mmo_charstatus *cd;
  3434. +		char* data;
  3435. +		int char_id;
  3436. +		uint32 subnet_map_ip;
  3437. +		struct auth_node* node;
  3438. +		int i, map_fd;
  3439. +
  3440. +		int slot = RFIFOB(fd,2);
  3441. +		RFIFOSKIP(fd,3);
  3442. +
  3443. +		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)
  3444. +		  || SQL_SUCCESS != Sql_NextRow(sql_handle)
  3445. +		  || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
  3446. +		{	//Not found?? May be forged packet.
  3447. +			Sql_ShowDebug(sql_handle);
  3448. +			Sql_FreeResult(sql_handle);
  3449. +			WFIFOHEAD(fd,3);
  3450. +			WFIFOW(fd,0) = 0x6c;
  3451. +			WFIFOB(fd,2) = 0; // rejected from server
  3452. +			WFIFOSET(fd,3);
  3453. +			return 0;
  3454. +		}
  3455. +
  3456. +		char_id = atoi(data);
  3457. +		Sql_FreeResult(sql_handle);
  3458. +
  3459. +		/* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
  3460. +		set_char_online(-2,char_id,sd->account_id);
  3461. +		if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
  3462. +			set_char_offline(char_id, sd->account_id);
  3463. +			/* failed to load something. REJECT! */
  3464. +			WFIFOHEAD(fd,3);
  3465. +			WFIFOW(fd,0) = 0x6c;
  3466. +			WFIFOB(fd,2) = 0;
  3467. +			WFIFOSET(fd,3);
  3468. +			return 0;/* jump off this boat */
  3469. +		}
  3470. +
  3471. +		//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
  3472. +		cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
  3473. +		cd->sex = sd->sex;
  3474. +
  3475. +		if (log_char) {
  3476. +			char esc_name[NAME_LENGTH*2+1];
  3477. +
  3478. +			Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
  3479. +			if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
  3480. +				charlog_db, sd->account_id, slot, esc_name) )
  3481. +				Sql_ShowDebug(sql_handle);
  3482. +		}
  3483. +		ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
  3484. +
  3485. +		// searching map server
  3486. +		i = search_mapserver(cd->last_point.map, -1, -1);
  3487. +
  3488. +		// if map is not found, we check major cities
  3489. +		if (i < 0 || !cd->last_point.map) {
  3490. +			unsigned short j;
  3491. +			//First check that there's actually a map server online.
  3492. +			ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
  3493. +			if (j == ARRAYLENGTH(server)) {
  3494. +				ShowInfo("Connection Closed. No map servers available.\n");
  3495. +				WFIFOHEAD(fd,3);
  3496. +				WFIFOW(fd,0) = 0x81;
  3497. +				WFIFOB(fd,2) = 1; // 01 = Server closed
  3498. +				WFIFOSET(fd,3);
  3499. +				return 0;
  3500. +			}
  3501. +			if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  3502. +				cd->last_point.x = 273;
  3503. +				cd->last_point.y = 354;
  3504. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  3505. +				cd->last_point.x = 120;
  3506. +				cd->last_point.y = 100;
  3507. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  3508. +				cd->last_point.x = 160;
  3509. +				cd->last_point.y = 94;
  3510. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  3511. +				cd->last_point.x = 116;
  3512. +				cd->last_point.y = 57;
  3513. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  3514. +				cd->last_point.x = 87;
  3515. +				cd->last_point.y = 117;
  3516. +			} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  3517. +				cd->last_point.x = 94;
  3518. +				cd->last_point.y = 103;
  3519. +			} else {
  3520. +				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));
  3521. +				WFIFOHEAD(fd,3);
  3522. +				WFIFOW(fd,0) = 0x81;
  3523. +				WFIFOB(fd,2) = 1; // 01 = Server closed
  3524. +				WFIFOSET(fd,3);
  3525. +				return 0;
  3526. +			}
  3527. +			ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  3528. +			cd->last_point.map = j;
  3529. +		}
  3530. +
  3531. +		//Send NEW auth packet [Kevin]
  3532. +		//FIXME: is this case even possible? [ultramage]
  3533. +		if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
  3534. +		{
  3535. +			ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  3536. +			server[i].fd = -1;
  3537. +			memset(&server[i], 0, sizeof(struct mmo_map_server));
  3538. +			//Send server closed.
  3539. +			WFIFOHEAD(fd,3);
  3540. +			WFIFOW(fd,0) = 0x81;
  3541. +			WFIFOB(fd,2) = 1; // 01 = Server closed
  3542. +			WFIFOSET(fd,3);
  3543. +			return 0;
  3544. +		}
  3545. +
  3546. +		//Send player to map
  3547. +		WFIFOHEAD(fd,28);
  3548. +		WFIFOW(fd,0) = 0x71;
  3549. +		WFIFOL(fd,2) = cd->char_id;
  3550. +		mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
  3551. +		subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
  3552. +		WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
  3553. +		WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  3554. +		WFIFOSET(fd,28);
  3555. +
  3556. +		// create temporary auth entry
  3557. +		CREATE(node, struct auth_node, 1);
  3558. +		node->account_id = sd->account_id;
  3559. +		node->char_id = cd->char_id;
  3560. +		node->login_id1 = sd->login_id1;
  3561. +		node->login_id2 = sd->login_id2;
  3562. +		node->sex = sd->sex;
  3563. +		node->expiration_time = sd->expiration_time;
  3564. +		node->group_id = sd->group_id;
  3565. +		node->ip = ipl;
  3566. +		idb_put(auth_db, sd->account_id, node);
  3567. +
  3568. +	}
  3569. +	return 1;
  3570. +}
  3571. +
  3572. +// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
  3573. +// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
  3574. +int char_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
  3575. +	int i=0, ch;
  3576. +
  3577. +	if (cmd == 0x970) FIFOSD_CHECK(31) //>=20120307
  3578. +	else if (cmd == 0x67) FIFOSD_CHECK(37)
  3579. +	else return 0;
  3580. +
  3581. +	if( !char_new ) //turn character creation on/off [Kevin]
  3582. +		i = -2;
  3583. +	else {
  3584. +		if (cmd == 0x970){
  3585. +			i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
  3586. +			RFIFOSKIP(fd,31);
  3587. +		}
  3588. +		else if(cmd == 0x67){
  3589. +#if PACKETVER < 20120307
  3590. +			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));
  3591. +			RFIFOSKIP(fd,37);
  3592. +#endif
  3593. +		}
  3594. +	}
  3595. +
  3596. +	//'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
  3597. +	if (i < 0) {
  3598. +		WFIFOHEAD(fd,3);
  3599. +		WFIFOW(fd,0) = 0x6e;
  3600. +		/* Others I found [Ind] */
  3601. +		/* 0x02 = Symbols in Character Names are forbidden */
  3602. +		/* 0x03 = You are not elegible to open the Character Slot. */
  3603. +		switch (i) {
  3604. +			case -1: WFIFOB(fd,2) = 0x00; break;
  3605. +			case -2: WFIFOB(fd,2) = 0xFF; break;
  3606. +			case -3: WFIFOB(fd,2) = 0x01; break;
  3607. +			case -4: WFIFOB(fd,2) = 0x03; break;
  3608. +		}
  3609. +		WFIFOSET(fd,3);
  3610. +	} else {
  3611. +		int len;
  3612. +		// retrieve data
  3613. +		struct mmo_charstatus char_dat;
  3614. +		mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
  3615. +
  3616. +		// send to player
  3617. +		WFIFOHEAD(fd,2+MAX_CHAR_BUF);
  3618. +		WFIFOW(fd,0) = 0x6d;
  3619. +		len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
  3620. +		WFIFOSET(fd,len);
  3621. +
  3622. +		// add new entry to the chars list
  3623. +		ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
  3624. +		if( ch < MAX_CHARS )
  3625. +			sd->found_char[ch] = i; // the char_id of the new char
  3626. +	}
  3627. +	return 1;
  3628. +}
  3629. +
  3630. +int char_parse_delchar(int fd,struct char_session_data* sd, int cmd){
  3631. +	char email[40];
  3632. +	int i, ch;
  3633. +
  3634. +	if (cmd == 0x68) FIFOSD_CHECK(46)
  3635. +	else if (cmd == 0x1fb) FIFOSD_CHECK(56)
  3636. +	else return 0;
  3637. +
  3638. +	{
  3639. +		int cid = RFIFOL(fd,2);
  3640. +
  3641. +		ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
  3642. +		memcpy(email, RFIFOP(fd,6), 40);
  3643. +		RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
  3644. +
  3645. +		// Check if e-mail is correct
  3646. +		if(strcmpi(email, sd->email) && //email does not matches and
  3647. +		(
  3648. +			strcmp("a@a.com", sd->email) || //it is not default email, or
  3649. +			(strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default
  3650. +		)) {	//Fail
  3651. +			WFIFOHEAD(fd,3);
  3652. +			WFIFOW(fd,0) = 0x70;
  3653. +			WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
  3654. +			WFIFOSET(fd,3);
  3655. +			return 0;
  3656. +		}
  3657. +
  3658. +		// check if this char exists
  3659. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  3660. +		if( i == MAX_CHARS )
  3661. +		{ // Such a character does not exist in the account
  3662. +			WFIFOHEAD(fd,3);
  3663. +			WFIFOW(fd,0) = 0x70;
  3664. +			WFIFOB(fd,2) = 0;
  3665. +			WFIFOSET(fd,3);
  3666. +			return 0;
  3667. +		}
  3668. +
  3669. +		// remove char from list and compact it
  3670. +		for(ch = i; ch < MAX_CHARS-1; ch++)
  3671. +			sd->found_char[ch] = sd->found_char[ch+1];
  3672. +		sd->found_char[MAX_CHARS-1] = -1;
  3673. +
  3674. +		/* Delete character */
  3675. +		if(delete_char_sql(cid)<0){
  3676. +			//can't delete the char
  3677. +			//either SQL error or can't delete by some CONFIG conditions
  3678. +			//del fail
  3679. +			WFIFOHEAD(fd,3);
  3680. +			WFIFOW(fd, 0) = 0x70;
  3681. +			WFIFOB(fd, 2) = 0;
  3682. +			WFIFOSET(fd, 3);
  3683. +			return 0;
  3684. +		}
  3685. +		/* Char successfully deleted.*/
  3686. +		WFIFOHEAD(fd,2);
  3687. +		WFIFOW(fd,0) = 0x6f;
  3688. +		WFIFOSET(fd,2);
  3689. +	}
  3690. +	return 1;
  3691. +}
  3692. +
  3693. +// R 0187 <account ID>.l
  3694. +int char_parse_keepalive(int fd){
  3695. +	if (RFIFOREST(fd) < 6)
  3696. +		return 0;
  3697. +	//int aid = RFIFOL(fd,2);
  3698. +	RFIFOSKIP(fd,6);
  3699. +	return 1;
  3700. +}
  3701. +
  3702. +// R 08fc <char ID>.l <new name>.24B
  3703. +// R 028d <account ID>.l <char ID>.l <new name>.24B
  3704. +int char_parse_reqrename(int fd, struct char_session_data* sd, int cmd){
  3705. +	if(cmd == 0x8fc) FIFOSD_CHECK(30)
  3706. +	if(cmd == 0x28d) FIFOSD_CHECK(34)
  3707. +	else return 0;
  3708. +
  3709. +	{
  3710. +		int i, cid=0;
  3711. +		char name[NAME_LENGTH];
  3712. +		char esc_name[NAME_LENGTH*2+1];
  3713. +		safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
  3714. +
  3715. +		if(cmd == 0x8fc){
  3716. +			cid =RFIFOL(fd,2);
  3717. +			RFIFOSKIP(fd,30);
  3718. +		}
  3719. +		else if(cmd == 0x28d) {
  3720. +			int aid = RFIFOL(fd,2);
  3721. +			cid =RFIFOL(fd,6);
  3722. +			if( aid != sd->account_id )
  3723. +				return 0;
  3724. +			RFIFOSKIP(fd,34);
  3725. +		}
  3726. +
  3727. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  3728. +		if( i == MAX_CHARS )
  3729. +			return 0;
  3730. +
  3731. +		normalize_name(name,TRIM_CHARS);
  3732. +		Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
  3733. +		if( !check_char_name(name,esc_name) )
  3734. +		{
  3735. +			i = 1;
  3736. +			safestrncpy(sd->new_name, name, NAME_LENGTH);
  3737. +		}
  3738. +		else
  3739. +			i = 0;
  3740. +
  3741. +		WFIFOHEAD(fd, 4);
  3742. +		WFIFOW(fd,0) = 0x28e;
  3743. +		WFIFOW(fd,2) = i;
  3744. +		WFIFOSET(fd,4);
  3745. +	}
  3746. +	return 1;
  3747. +}
  3748. +
  3749. +// 0x28f <char_id>.L
  3750. +int char_parse_ackrename(int fd, struct char_session_data* sd){
  3751. +	// 0: Sucessfull
  3752. +	// 1: This character's name has already been changed. You cannot change a character's name more than once.
  3753. +	// 2: User information is not correct.
  3754. +	// 3: You have failed to change this character's name.
  3755. +	// 4: Another user is using this character name, so please select another one.
  3756. +	FIFOSD_CHECK(6)
  3757. +
  3758. +	{
  3759. +		int i;
  3760. +		int cid = RFIFOL(fd,2);
  3761. +		RFIFOSKIP(fd,6);
  3762. +
  3763. +		ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
  3764. +		if( i == MAX_CHARS )
  3765. +			return 0;
  3766. +		i = rename_char_sql(sd, cid);
  3767. +
  3768. +		WFIFOHEAD(fd, 4);
  3769. +		WFIFOW(fd,0) = 0x290;
  3770. +		WFIFOW(fd,2) = i;
  3771. +		WFIFOSET(fd,4);
  3772. +	}
  3773. +	return 1;
  3774. +}
  3775. +
  3776. +// R 07e5 <?>.w <aid>.l
  3777. +int char_parse_reqcaptcha(int fd){
  3778. +	WFIFOHEAD(fd,5);
  3779. +	WFIFOW(fd,0) = 0x7e9;
  3780. +	WFIFOW(fd,2) = 5;
  3781. +	WFIFOB(fd,4) = 1;
  3782. +	WFIFOSET(fd,5);
  3783. +	RFIFOSKIP(fd,8);
  3784. +	return 1;
  3785. +}
  3786. +
  3787. +// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
  3788. +int char_parse_chkcaptcha(int fd){
  3789. +	WFIFOHEAD(fd,5);
  3790. +	WFIFOW(fd,0) = 0x7e9;
  3791. +	WFIFOW(fd,2) = 5;
  3792. +	WFIFOB(fd,4) = 1;
  3793. +	WFIFOSET(fd,5);
  3794. +	RFIFOSKIP(fd,32);
  3795. +	return 1;
  3796. +}
  3797. +
  3798. +
  3799. +int parse_char(int fd)
  3800. +{
  3801. +	unsigned short cmd;
  3802. +	struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
  3803. +	uint32 ipl = session[fd]->client_addr;
  3804. +
  3805. +	// disconnect any player if no login-server.
  3806. +	if(login_fd < 0)
  3807. +		set_eof(fd);
  3808. +
  3809. +	if(session[fd]->flag.eof)
  3810. +	{
  3811. +		if( sd != NULL && sd->auth )
  3812. +		{	// already authed client
  3813. +			struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
  3814. +			if( data != NULL && data->fd == fd)
  3815. +				data->fd = -1;
  3816. +			if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
  3817. +				set_char_offline(-1,sd->account_id);
  3818. +		}
  3819. +		do_close(fd);
  3820. +		return 0;
  3821. +	}
  3822. +
  3823. +	while( RFIFOREST(fd) >= 2 )
  3824. +	{
  3825. +		cmd = RFIFOW(fd,0);
  3826. +		switch( cmd )
  3827. +		{
  3828. +
  3829. +		case 0x65: char_parse_reqtoconnect(fd,sd,ipl); break;
  3830. +		// char select
  3831. +		case 0x66: char_parse_charselect(fd,sd,ipl); break;
  3832. +		// createnewchar
  3833. +		case 0x970: char_parse_createnewchar(fd,sd,cmd); break;
  3834. +		case 0x67: char_parse_createnewchar(fd,sd,cmd); break;
  3835. +		// delete char
  3836. +		case 0x68: char_parse_delchar(fd,sd,cmd); break; //
  3837. +		case 0x1fb: char_parse_delchar(fd,sd,cmd); break; // 2004-04-19aSakexe+ langtype 12 char deletion packet
  3838. +		// client keep-alive packet (every 12 seconds)
  3839. +		case 0x187: char_parse_keepalive(fd); break;
  3840. +		// char rename
  3841. +		case 0x8fc: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  3842. +		case 0x28d: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
  3843. +		case 0x28f: char_parse_ackrename(fd,sd); break; //Confirm change name.
  3844. +		// captcha
  3845. +		case 0x7e5: char_parse_reqcaptcha(fd); break; // captcha code request (not implemented)
  3846. +		case 0x7e7: char_parse_chkcaptcha(fd); break; // captcha code check (not implemented)
  3847. +		// deletion timer request
  3848. +		case 0x827: char_parse_delete2_req(fd, sd); break;
  3849. +		// deletion accept request
  3850. +		case 0x829: char_parse_delete2_accept(fd, sd); break;
  3851. +		// deletion cancel request
  3852. +		case 0x82b: char_parse_delete2_cancel(fd, sd); break;
  3853. +		// login as map-server
  3854. +		case 0x2af8: char_parse_maplogin(fd); return 0; // avoid processing of followup packets here
  3855. +		//pincode
  3856. +		case 0x8b8: char_parse_pincode_check( fd, sd ); break; // checks the entered pin
  3857. +		case 0x8c5: char_parse_reqpincode_window(fd,sd); break; // request for PIN window
  3858. +		case 0x8be: char_parse_pincode_change( fd, sd ); break; // pincode change request
  3859. +		case 0x8ba: char_parse_pincode_setnew( fd, sd ); break; // activate PIN system and set first PIN
  3860. +		// character movement request
  3861. +		case 0x8d4: char_parse_moveCharSlot(fd,sd); break;
  3862. +		case 0x9a1: char_parse_req_charlist(fd,sd); break;
  3863. +		// unknown packet received
  3864. +		default:
  3865. +			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));
  3866. +			set_eof(fd);
  3867. +			return 0;
  3868. +		}
  3869. +	}
  3870. +
  3871. +	RFIFOFLUSH(fd);
  3872. +	return 0;
  3873. +}
  3874. +
  3875. +///
  3876. +/// Login IF
  3877. +///
  3878. +
  3879. +int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
  3880. +{
  3881. +	if (login_fd > 0 && session[login_fd] != NULL)
  3882. +		return 0;
  3883. +
  3884. +	ShowInfo("Attempt to connect to login-server...\n");
  3885. +	login_fd = make_connection(login_ip, login_port, false,10);
  3886. +	if (login_fd == -1)
  3887. +	{	//Try again later. [Skotlex]
  3888. +		login_fd = 0;
  3889. +		return 0;
  3890. +	}
  3891. +	session[login_fd]->func_parse = parse_fromlogin;
  3892. +	session[login_fd]->flag.server = 1;
  3893. +	realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  3894. +
  3895. +	WFIFOHEAD(login_fd,86);
  3896. +	WFIFOW(login_fd,0) = 0x2710;
  3897. +	memcpy(WFIFOP(login_fd,2), userid, 24);
  3898. +	memcpy(WFIFOP(login_fd,26), passwd, 24);
  3899. +	WFIFOL(login_fd,50) = 0;
  3900. +	WFIFOL(login_fd,54) = htonl(char_ip);
  3901. +	WFIFOW(login_fd,58) = htons(char_port);
  3902. +	memcpy(WFIFOP(login_fd,60), server_name, 20);
  3903. +	WFIFOW(login_fd,80) = 0;
  3904. +	WFIFOW(login_fd,82) = char_maintenance;
  3905. +	WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
  3906. +	WFIFOSET(login_fd,86);
  3907. +
  3908. +	return 1;
  3909. +}
  3910. +
  3911. +int char_parselog_ackconnect(int fd, struct char_session_data* sd){
  3912. +	if (RFIFOREST(fd) < 3)
  3913. +		return 0;
  3914. +
  3915. +	if (RFIFOB(fd,2)) {
  3916. +		//printf("connect login server error : %d\n", RFIFOB(fd,2));
  3917. +		ShowError("Can not connect to login-server.\n");
  3918. +		ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  3919. +		ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
  3920. +		ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
  3921. +		set_eof(fd);
  3922. +		return 0;
  3923. +	} else {
  3924. +		ShowStatus("Connected to login-server (connection #%d).\n", fd);
  3925. +		loginif_on_ready();
  3926. +	}
  3927. +	RFIFOSKIP(fd,3);
  3928. +	return 1;
  3929. +}
  3930. +
  3931. +int char_parselog_ackaccreq(int fd, struct char_session_data* sd){
  3932. +	if (RFIFOREST(fd) < 25)
  3933. +		return 0;
  3934. +	{
  3935. +		int account_id = RFIFOL(fd,2);
  3936. +		uint32 login_id1 = RFIFOL(fd,6);
  3937. +		uint32 login_id2 = RFIFOL(fd,10);
  3938. +		uint8 sex = RFIFOB(fd,14);
  3939. +		uint8 result = RFIFOB(fd,15);
  3940. +		int request_id = RFIFOL(fd,16);
  3941. +		uint32 version = RFIFOL(fd,20);
  3942. +		uint8 clienttype = RFIFOB(fd,24);
  3943. +		RFIFOSKIP(fd,25);
  3944. +
  3945. +		if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
  3946. +			!sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
  3947. +		{
  3948. +			int client_fd = request_id;
  3949. +			sd->version = version;
  3950. +			sd->clienttype = clienttype;
  3951. +			switch( result )
  3952. +			{
  3953. +			case 0:// ok
  3954. +				char_auth_ok(client_fd, sd);
  3955. +				break;
  3956. +			case 1:// auth failed
  3957. +				WFIFOHEAD(client_fd,3);
  3958. +				WFIFOW(client_fd,0) = 0x6c;
  3959. +				WFIFOB(client_fd,2) = 0;// rejected from server
  3960. +				WFIFOSET(client_fd,3);
  3961. +				break;
  3962. +			}
  3963. +		}
  3964. +	}
  3965. +	return 1;
  3966. +}
  3967. +
  3968. +int char_parselog_reqaccdata(int fd, struct char_session_data* sd){
  3969. +	int i;
  3970. +	if (RFIFOREST(fd) < 73)
  3971. +		return 0;
  3972. +
  3973. +	// find the authenticated session with this account id
  3974. +	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) );
  3975. +	if( i < fd_max )
  3976. +	{
  3977. +		int server_id;
  3978. +		memcpy(sd->email, RFIFOP(fd,6), 40);
  3979. +		sd->expiration_time = (time_t)RFIFOL(fd,46);
  3980. +		sd->group_id = RFIFOB(fd,50);
  3981. +		sd->char_slots = RFIFOB(fd,51);
  3982. +		if( sd->char_slots > MAX_CHARS ) {
  3983. +			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);
  3984. +			sd->char_slots = MAX_CHARS;/* cap to maximum */
  3985. +		} else if ( !sd->char_slots )/* no value aka 0 in sql */
  3986. +			sd->char_slots = MAX_CHARS;/* cap to maximum */
  3987. +		safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
  3988. +		safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
  3989. +		sd->pincode_change = (time_t)RFIFOL(fd,68);
  3990. +		sd->version = RFIFOB(fd,72);
  3991. +		ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
  3992. +		// continued from char_auth_ok...
  3993. +		if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
  3994. +			(max_connect_user == 0 && sd->group_id != gm_allow_group) ||
  3995. +			( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
  3996. +			// refuse connection (over populated)
  3997. +			WFIFOHEAD(i,3);
  3998. +			WFIFOW(i,0) = 0x6c;
  3999. +			WFIFOW(i,2) = 0;
  4000. +			WFIFOSET(i,3);
  4001. +		} else {
  4002. +			// send characters to player
  4003. +			mmo_char_send(i, sd);
  4004. +#if PACKETVER >=  20110309
  4005. +			if( pincode_enabled ){
  4006. +				// PIN code system enabled
  4007. +				if( strlen( sd->pincode ) <= 0 ){
  4008. +					// No PIN code has been set yet
  4009. +					if( pincode_force ){
  4010. +						pincode_sendstate( i, sd, PINCODE_NEW );
  4011. +					}else{
  4012. +						pincode_sendstate( i, sd, PINCODE_PASSED );
  4013. +					}
  4014. +				}else{
  4015. +					if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
  4016. +						struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
  4017. +
  4018. +						if( node != NULL && node->pincode_success ){
  4019. +							// User has already passed the check
  4020. +							pincode_sendstate( i, sd, PINCODE_PASSED );
  4021. +						}else{
  4022. +							// Ask user for his PIN code
  4023. +							pincode_sendstate( i, sd, PINCODE_ASK );
  4024. +						}
  4025. +					}else{
  4026. +						// User hasnt changed his PIN code too long
  4027. +						pincode_sendstate( i, sd, PINCODE_EXPIRED );
  4028. +					}
  4029. +				}
  4030. +			}else{
  4031. +				// PIN code system disabled
  4032. +				pincode_sendstate( i, sd, PINCODE_OK );
  4033. +			}
  4034. +#endif
  4035. +		}
  4036. +	}
  4037. +	RFIFOSKIP(fd,73);
  4038. +	return 1;
  4039. +}
  4040. +
  4041. +int char_parselog_keepalive(int fd, struct char_session_data* sd){
  4042. +	if (RFIFOREST(fd) < 2)
  4043. +		return 0;
  4044. +	RFIFOSKIP(fd,2);
  4045. +	session[fd]->flag.ping = 0;
  4046. +	return 1;
  4047. +}
  4048. +
  4049. +int char_parselog_ackchangesex(int fd, struct char_session_data* sd){
  4050. +	if (RFIFOREST(fd) < 7)
  4051. +		return 0;
  4052. +	{
  4053. +		unsigned char buf[7];
  4054. +		int i;
  4055. +
  4056. +		int acc = RFIFOL(fd,2);
  4057. +		int sex = RFIFOB(fd,6);
  4058. +		RFIFOSKIP(fd,7);
  4059. +
  4060. +		if( acc > 0 )
  4061. +		{// TODO: Is this even possible?
  4062. +			int char_id[MAX_CHARS];
  4063. +			int class_[MAX_CHARS];
  4064. +			int guild_id[MAX_CHARS];
  4065. +			int num;
  4066. +			char* data;
  4067. +
  4068. +			struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
  4069. +			if( node != NULL )
  4070. +				node->sex = sex;
  4071. +
  4072. +			// get characters
  4073. +			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
  4074. +				Sql_ShowDebug(sql_handle);
  4075. +			for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
  4076. +			{
  4077. +				Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
  4078. +				Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
  4079. +				Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
  4080. +			}
  4081. +			num = i;
  4082. +			for( i = 0; i < num; ++i )
  4083. +			{
  4084. +				if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
  4085. +					class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
  4086. +					class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
  4087. +					class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
  4088. +					class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
  4089. +					class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
  4090. +					class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  4091. +				{
  4092. +					// job modification
  4093. +					if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
  4094. +						class_[i] = (sex ? JOB_BARD : JOB_DANCER);
  4095. +					else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
  4096. +						class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
  4097. +					else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
  4098. +						class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
  4099. +					else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
  4100. +						class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
  4101. +					else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
  4102. +						class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
  4103. +					else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
  4104. +						class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
  4105. +					else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
  4106. +						class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
  4107. +				}
  4108. +
  4109. +				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]) )
  4110. +					Sql_ShowDebug(sql_handle);
  4111. +
  4112. +				if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
  4113. +					inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
  4114. +			}
  4115. +			Sql_FreeResult(sql_handle);
  4116. +
  4117. +			// disconnect player if online on char-server
  4118. +			disconnect_player(acc);
  4119. +		}
  4120. +
  4121. +		// notify all mapservers about this change
  4122. +		WBUFW(buf,0) = 0x2b0d;
  4123. +		WBUFL(buf,2) = acc;
  4124. +		WBUFB(buf,6) = sex;
  4125. +		mapif_sendall(buf, 7);
  4126. +	}
  4127. +	return 1;
  4128. +}
  4129. +
  4130. +int char_parselog_ackacc2req(int fd, struct char_session_data* sd){
  4131. +	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  4132. +		return 0;
  4133. +
  4134. +	{	//Receive account_reg2 registry, forward to map servers.
  4135. +		unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
  4136. +		memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  4137. +		WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  4138. +		mapif_sendall(buf, WBUFW(buf,2));
  4139. +		RFIFOSKIP(fd, RFIFOW(fd,2));
  4140. +	}
  4141. +	return 1;
  4142. +}
  4143. +
  4144. +int char_parselog_accbannotification(int fd, struct char_session_data* sd){
  4145. +	if (RFIFOREST(fd) < 11)
  4146. +		return 0;
  4147. +
  4148. +	{	// send to all map-servers to disconnect the player
  4149. +		unsigned char buf[11];
  4150. +		WBUFW(buf,0) = 0x2b14;
  4151. +		WBUFL(buf,2) = RFIFOL(fd,2);
  4152. +		WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  4153. +		WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  4154. +		mapif_sendall(buf, 11);
  4155. +	}
  4156. +	// disconnect player if online on char-server
  4157. +	disconnect_player(RFIFOL(fd,2));
  4158. +	RFIFOSKIP(fd,11);
  4159. +	return 1;
  4160. +}
  4161. +
  4162. +int char_parselog_askkick(int fd, struct char_session_data* sd){
  4163. +	if (RFIFOREST(fd) < 6)
  4164. +		return 0;
  4165. +	{
  4166. +		int aid = RFIFOL(fd,2);
  4167. +		struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
  4168. +		RFIFOSKIP(fd,6);
  4169. +		if( character != NULL )
  4170. +		{// account is already marked as online!
  4171. +			if( character->server > -1 )
  4172. +			{	//Kick it from the map server it is on.
  4173. +				mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
  4174. +				if (character->waiting_disconnect == INVALID_TIMER)
  4175. +					character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
  4176. +			}
  4177. +			else
  4178. +			{// Manual kick from char server.
  4179. +				struct char_session_data *tsd;
  4180. +				int i;
  4181. +				ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
  4182. +				if( i < fd_max )
  4183. +				{
  4184. +					WFIFOHEAD(i,3);
  4185. +					WFIFOW(i,0) = 0x81;
  4186. +					WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
  4187. +					WFIFOSET(i,3);
  4188. +					set_eof(i);
  4189. +				}
  4190. +				else // still moving to the map-server
  4191. +					set_char_offline(-1, aid);
  4192. +			}
  4193. +		}
  4194. +		idb_remove(auth_db, aid);// reject auth attempts from map-server
  4195. +	}
  4196. +	return 1;
  4197. +}
  4198. +
  4199. +int char_parselog_updip(int fd, struct char_session_data* sd){
  4200. +	if (RFIFOREST(fd) < 2)
  4201. +		return 0;
  4202. +	{
  4203. +		unsigned char buf[2];
  4204. +		uint32 new_ip = 0;
  4205. +
  4206. +		WBUFW(buf,0) = 0x2b1e;
  4207. +		mapif_sendall(buf, 2);
  4208. +
  4209. +		new_ip = host2ip(login_ip_str);
  4210. +		if (new_ip && new_ip != login_ip)
  4211. +			login_ip = new_ip; //Update login ip, too.
  4212. +
  4213. +		new_ip = host2ip(char_ip_str);
  4214. +		if (new_ip && new_ip != char_ip)
  4215. +		{	//Update ip.
  4216. +			char_ip = new_ip;
  4217. +			ShowInfo("Updating IP for [%s].\n", char_ip_str);
  4218. +			// notify login server about the change
  4219. +			WFIFOHEAD(fd,6);
  4220. +			WFIFOW(fd,0) = 0x2736;
  4221. +			WFIFOL(fd,2) = htonl(char_ip);
  4222. +			WFIFOSET(fd,6);
  4223. +		}
  4224. +
  4225. +		RFIFOSKIP(fd,2);
  4226. +	}
  4227. +	return 1;
  4228. +}
  4229. +
  4230. +int parse_fromlogin(int fd) {
  4231. +	struct char_session_data* sd = NULL;
  4232. +
  4233. +	// only process data from the login-server
  4234. +	if( fd != login_fd ) {
  4235. +		ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
  4236. +		do_close(fd);
  4237. +		return 0;
  4238. +	}
  4239. +
  4240. +	if( session[fd]->flag.eof ) {
  4241. +		do_close(fd);
  4242. +		login_fd = -1;
  4243. +		loginif_on_disconnect();
  4244. +		return 0;
  4245. +	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
  4246. +		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
  4247. +			set_eof(fd);
  4248. +			return 0;
  4249. +		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
  4250. +			WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
  4251. +			WFIFOW(fd,0) = 0x2719;
  4252. +			WFIFOSET(fd,2);
  4253. +
  4254. +			session[fd]->flag.ping = 2;
  4255. +		}
  4256. +	}
  4257. +
  4258. +	sd = (struct char_session_data*)session[fd]->session_data;
  4259. +
  4260. +	while(RFIFOREST(fd) >= 2) {
  4261. +		uint16 command = RFIFOW(fd,0);
  4262. +
  4263. +		switch( command )
  4264. +		{
  4265. +		// acknowledgement of connect-to-loginserver request
  4266. +		case 0x2711: char_parselog_ackconnect(fd,sd); break;
  4267. +		// acknowledgement of account authentication request
  4268. +		case 0x2713: char_parselog_ackaccreq(fd, sd); break;
  4269. +		// account data
  4270. +		case 0x2717: char_parselog_reqaccdata(fd, sd); break;
  4271. +		// login-server alive packet
  4272. +		case 0x2718: char_parselog_keepalive(fd, sd); break;
  4273. +		// changesex reply
  4274. +		case 0x2723: char_parselog_ackchangesex(fd, sd); break;
  4275. +		// reply to an account_reg2 registry request
  4276. +		case 0x2729: char_parselog_ackacc2req(fd, sd); break;
  4277. +		// State change of account/ban notification (from login-server)
  4278. +		case 0x2731: char_parselog_accbannotification(fd, sd); break;
  4279. +		// Login server request to kick a character out. [Skotlex]
  4280. +		case 0x2734: char_parselog_askkick(fd,sd); break;
  4281. +		// ip address update signal from login server
  4282. +		case 0x2735: char_parselog_updip(fd,sd); break;
  4283. +		default:
  4284. +			ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
  4285. +			set_eof(fd);
  4286. +			return 0;
  4287. +		}
  4288. +	}
  4289. +
  4290. +	RFIFOFLUSH(fd);
  4291. +	return 0;
  4292. +}
  4293. +
  4294. +
  4295. +
  4296. +
  4297. +/*======================================================
  4298. + * Login-Server help option info
  4299. + *------------------------------------------------------*/
  4300. +void display_helpscreen(bool do_exit)
  4301. +{
  4302. +	ShowInfo("Usage: %s [options]\n", SERVER_NAME);
  4303. +	ShowInfo("\n");
  4304. +	ShowInfo("Options:\n");
  4305. +	ShowInfo("  -?, -h [--help]\t\tDisplays this help screen.\n");
  4306. +	ShowInfo("  -v [--version]\t\tDisplays the server's version.\n");
  4307. +	ShowInfo("  --run-once\t\t\tCloses server after loading (testing).\n");
  4308. +	ShowInfo("  --char-config <file>\t\tAlternative char-server configuration.\n");
  4309. +	ShowInfo("  --lan-config <file>\t\tAlternative lag configuration.\n");
  4310. +	ShowInfo("  --inter-config <file>\t\tAlternative inter-server configuration.\n");
  4311. +	ShowInfo("  --msg-config <file>\t\tAlternative message configuration.\n");
  4312. +	if( do_exit )
  4313. +		exit(EXIT_SUCCESS);
  4314. +}
  4315. +
  4316. +int char_msg_config_read(char *cfgName){
  4317. +	return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
  4318. +}
  4319. +const char* char_msg_txt(int msg_number){
  4320. +	return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
  4321. +}
  4322. +void char_do_final_msg(void){
  4323. +	_do_final_msg(CHAR_MAX_MSG,msg_table);
  4324. +}
  4325. +
  4326. +
  4327. +
  4328.  void do_final(void)
  4329.  {
  4330.  	ShowStatus("Terminating...\n");
  4331. @@ -5188,6 +5304,12 @@
  4332.  	ShowStatus("Finished.\n");
  4333.  }
  4334.  
  4335. +
  4336. +void set_server_type(void)
  4337. +{
  4338. +	SERVER_TYPE = ATHENA_SERVER_CHAR;
  4339. +}
  4340. +
  4341.  //------------------------------
  4342.  // Function called when the server
  4343.  // has received a crash signal.
  4344. @@ -5196,12 +5318,6 @@
  4345.  {
  4346.  }
  4347.  
  4348. -void set_server_type(void)
  4349. -{
  4350. -	SERVER_TYPE = ATHENA_SERVER_CHAR;
  4351. -}
  4352. -
  4353. -
  4354.  /// Called when a terminate signal is received.
  4355.  void do_shutdown(void)
  4356.  {
  4357. @@ -5317,33 +5433,4 @@
  4358.  		add_timer_interval(gettick()+1000, parse_console_timer, 0, 0, 1000); //start in 1s each 1sec
  4359.  	}
  4360.  	return 0;
  4361. -}
  4362. -
  4363. -int char_msg_config_read(char *cfgName){
  4364. -	return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
  4365. -}
  4366. -const char* char_msg_txt(int msg_number){
  4367. -	return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
  4368. -}
  4369. -void char_do_final_msg(void){
  4370. -	_do_final_msg(CHAR_MAX_MSG,msg_table);
  4371. -}
  4372. -
  4373. -/*======================================================
  4374. - * Login-Server help option info
  4375. - *------------------------------------------------------*/
  4376. -void display_helpscreen(bool do_exit)
  4377. -{
  4378. -	ShowInfo("Usage: %s [options]\n", SERVER_NAME);
  4379. -	ShowInfo("\n");
  4380. -	ShowInfo("Options:\n");
  4381. -	ShowInfo("  -?, -h [--help]\t\tDisplays this help screen.\n");
  4382. -	ShowInfo("  -v [--version]\t\tDisplays the server's version.\n");
  4383. -	ShowInfo("  --run-once\t\t\tCloses server after loading (testing).\n");
  4384. -	ShowInfo("  --char-config <file>\t\tAlternative char-server configuration.\n");
  4385. -	ShowInfo("  --lan-config <file>\t\tAlternative lag configuration.\n");
  4386. -	ShowInfo("  --inter-config <file>\t\tAlternative inter-server configuration.\n");
  4387. -	ShowInfo("  --msg-config <file>\t\tAlternative message configuration.\n");
  4388. -	if( do_exit )
  4389. -		exit(EXIT_SUCCESS);
  4390. -}
  4391. +}
  4392. \ No newline at end of file
  4393.  
Viewed 831 times, submitted by lighta.