Index: conf/login_athena.conf
===================================================================
--- conf/login_athena.conf (revision 17365)
+++ conf/login_athena.conf (working copy)
@@ -82,7 +82,7 @@
check_client_version: no
// What version we would allow to connect? (if the options above is enabled..)
-client_version_to_connect: 20
+client_version_to_connect: 30
// Store passwords as MD5 hashes instead of plaintext ?
// NOTE: Will not work with clients that use <passwordencrypt>
@@ -149,13 +149,14 @@
// If turned on, the login server will check if the client's hash matches
// the value below, and will not connect tampered clients.
// Note: see doc\md5_hashcheck.txt for more details.
-client_hash_check: off
+client_hash_check: yes
// Client MD5 hashes
// A player can login with a client hash at or below the account group_id.
// Format: group_id, hash
client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5
-client_hash: 99, cb1ea78023d337c38e8ba5124e2338ae
+client_hash: 98, cb1ea78023d337c38e8ba5124e2338ae
+client_hash: 99, any
import: conf/inter_athena.conf
import: conf/import/login_conf.txt
Index: src/login/login.c
===================================================================
--- src/login/login.c (revision 17365)
+++ src/login/login.c (working copy)
@@ -13,6 +13,7 @@
#include "../common/msg_conf.h"
#include "../common/cli.h"
#include "../common/ers.h"
+#include "../common/utils.h"
#include "account.h"
#include "ipban.h"
#include "login.h"
@@ -77,7 +78,6 @@
#define AUTH_TIMEOUT 30000
struct auth_node {
-
int account_id;
uint32 login_id1;
uint32 login_id2;
@@ -86,7 +86,6 @@
uint32 version;
uint8 clienttype;
};
-
static DBMap* auth_db; // int account_id -> struct auth_node*
@@ -94,13 +93,12 @@
// Online User Database [Wizputer]
//-----------------------------------------------------
struct online_login_data {
-
int account_id;
int waiting_disconnect;
int char_server;
};
+static DBMap* online_db; // int account_id -> struct online_login_data*
-static DBMap* online_db; // int account_id -> struct online_login_data*
static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data);
/**
@@ -191,7 +189,85 @@
return 0;
}
+//--------------------------------------------
+// Test to know if an IP come from LAN or WAN.
+//--------------------------------------------
+int lan_subnetcheck(uint32 ip)
+{
+ int i;
+ ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
+ return ( i < subnet_count ) ? subnet[i].char_ip : 0;
+}
+//-----------------------
+// Console Command Parser [Wizputer]
+//-----------------------
+int parse_console(const char* buf){
+ char type[64];
+ char command[64];
+ int n=0;
+
+ if( ( n = sscanf(buf, "%127[^:]:%255[^\n\r]", type, command) ) < 2 ){
+ if((n = sscanf(buf, "%63[^\n]", type))<1) return -1; //nothing to do no arg
+ }
+ if( n != 2 ){ //end string
+ ShowNotice("Type: '%s'\n",type);
+ command[0] = '\0';
+ }
+ else
+ ShowNotice("Type of command: '%s' || Command: '%s'\n",type,command);
+
+ if( n == 2 ){
+ if(strcmpi("server", type) == 0 ){
+ if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 ){
+ runflag = 0;
+ }
+ else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 )
+ ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n");
+ }
+ if( strcmpi("create",type) == 0 )
+ {
+ char username[NAME_LENGTH], password[NAME_LENGTH], md5password[32+1], sex; //23+1 plaintext 32+1 md5
+ bool md5 = 0;
+ if( sscanf(command, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ){
+ ShowWarning("Console: Invalid parameters for '%s'. Usage: %s <username> <password> <sex:F/M>\n", type, type);
+ return 0;
+ }
+ if( login_config.use_md5_passwds ){
+ MD5_String(password,md5password);
+ md5 = 1;
+ }
+ if( mmo_auth_new(username,(md5?md5password:password), TOUPPER(sex), "0.0.0.0") != -1 ){
+ ShowError("Console: Account creation failed.\n");
+ return 0;
+ }
+ ShowStatus("Console: Account '%s' created successfully.\n", username);
+ }
+ }
+ else if( strcmpi("ers_report", type) == 0 ){
+ ers_report();
+ }
+ else if( strcmpi("help", type) == 0 ){
+ ShowInfo("Available commands:\n");
+ ShowInfo("\t server:shutdown => Stops the server.\n");
+ ShowInfo("\t server:alive => Checks if the server is running.\n");
+ ShowInfo("\t ers_report => Displays database usage.\n");
+ ShowInfo("\t create:<username> <password> <sex:M|F> => Creates a new account.\n");
+ }
+ else{ // commands with parameters
+
+
+
+ }
+
+ return 0;
+}
+
+
+///
+/// Char IF
+///
+
//--------------------------------------------------------------------
// Packet send to all char-servers, except one (wos: without our self)
//--------------------------------------------------------------------
@@ -242,7 +318,6 @@
chrif_server_init(id);
}
-
/// Called when the connection to Char Server is disconnected.
void chrif_on_disconnect(int id)
{
@@ -250,7 +325,6 @@
chrif_server_reset(id);
}
-
//-----------------------------------------------------
// periodic ip address synchronization
//-----------------------------------------------------
@@ -263,684 +337,576 @@
return 0;
}
+int login_parsechar_reqauth(int fd, int id,char* ip){
+ if( RFIFOREST(fd) < 23 )
+ return 0;
+ else{
+ struct auth_node* node;
+ int account_id = RFIFOL(fd,2);
+ uint32 login_id1 = RFIFOL(fd,6);
+ uint32 login_id2 = RFIFOL(fd,10);
+ uint8 sex = RFIFOB(fd,14);
+ //uint32 ip_ = ntohl(RFIFOL(fd,15));
+ int request_id = RFIFOL(fd,19);
+ RFIFOSKIP(fd,23);
-//-----------------------------------------------------
-// encrypted/unencrypted password check (from eApp)
-//-----------------------------------------------------
-bool check_encrypted(const char* str1, const char* str2, const char* passwd)
-{
- char tmpstr[64+1], md5str[32+1];
+ node = (struct auth_node*)idb_get(auth_db, account_id);
+ if( runflag == LOGINSERVER_ST_RUNNING &&
+ node != NULL &&
+ node->account_id == account_id &&
+ node->login_id1 == login_id1 &&
+ node->login_id2 == login_id2 &&
+ node->sex == sex_num2str(sex) /*&&
+ node->ip == ip_*/ ){// found
+ //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip);
- safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
- MD5_String(tmpstr, md5str);
+ // send ack
+ WFIFOHEAD(fd,25);
+ WFIFOW(fd,0) = 0x2713;
+ WFIFOL(fd,2) = account_id;
+ WFIFOL(fd,6) = login_id1;
+ WFIFOL(fd,10) = login_id2;
+ WFIFOB(fd,14) = sex;
+ WFIFOB(fd,15) = 0;// ok
+ WFIFOL(fd,16) = request_id;
+ WFIFOL(fd,20) = node->version;
+ WFIFOB(fd,24) = node->clienttype;
+ WFIFOSET(fd,25);
- return (0==strcmp(passwd, md5str));
+ // each auth entry can only be used once
+ idb_remove(auth_db, account_id);
+ }else{// authentication not found
+ ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip);
+ WFIFOHEAD(fd,25);
+ WFIFOW(fd,0) = 0x2713;
+ WFIFOL(fd,2) = account_id;
+ WFIFOL(fd,6) = login_id1;
+ WFIFOL(fd,10) = login_id2;
+ WFIFOB(fd,14) = sex;
+ WFIFOB(fd,15) = 1;// auth failed
+ WFIFOL(fd,16) = request_id;
+ WFIFOL(fd,20) = 0;
+ WFIFOB(fd,24) = 0;
+ WFIFOSET(fd,25);
+ }
+ }
+ return 1;
}
-bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass)
-{
- if(passwdenc == 0)
- {
- return (0==strcmp(passwd, refpass));
- }
- else
- {
- // password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
- // password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
+int login_parsechar_ackusercount(int fd, int id){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ else{
+ int users = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
- return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) ||
- ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd));
+ // how many users on world? (update)
+ if( server[id].users != users ){
+ ShowStatus("set users %s : %d\n", server[id].name, users);
+
+ server[id].users = users;
+ }
}
+ return 1;
}
+int login_parsechar_updmail(int fd, int id, char* ip){
+ if (RFIFOREST(fd) < 46)
+ return 0;
+ else{
+ struct mmo_account acc;
+ char email[40];
-//-----------------------------------------------------
-// custom timestamp formatting (from eApp)
-//-----------------------------------------------------
-const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
-{
- size_t len = strftime(str, size, format, localtime(×tamp));
- memset(str + len, '\0', size - len);
- return str;
-}
+ int account_id = RFIFOL(fd,2);
+ safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email);
+ RFIFOSKIP(fd,46);
-
-//--------------------------------------------
-// Test to know if an IP come from LAN or WAN.
-//--------------------------------------------
-int lan_subnetcheck(uint32 ip)
-{
- int i;
- ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
- return ( i < subnet_count ) ? subnet[i].char_ip : 0;
+ if( e_mail_check(email) == 0 )
+ ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip);
+ else if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "[email protected]") == 0 || acc.email[0] == '\0' )
+ ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip);
+ else{
+ memcpy(acc.email, email, 40);
+ ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip);
+ // Save
+ accounts->save(accounts, &acc);
+ }
+ }
+ return 1;
}
-//----------------------------------
-// Reading Lan Support configuration
-//----------------------------------
-int login_lan_config_read(const char *lancfgName)
-{
- FILE *fp;
- int line_num = 0;
- char line[1024], w1[64], w2[64], w3[64], w4[64];
+int login_parsechar_reqaccdata(int fd, int id, char *ip){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ else{
+ struct mmo_account acc;
+ time_t expiration_time = 0;
+ char email[40] = "";
+ uint8 char_slots = 0;
+ int group_id = 0;
+ char birthdate[10+1] = "";
+ char pincode[PINCODE_LENGTH+1];
+ int account_id = RFIFOL(fd,2);
+ int cl_version = date2version(PACKETVER);
- if((fp = fopen(lancfgName, "r")) == NULL) {
- ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
- return 1;
- }
+ memset(pincode,0,PINCODE_LENGTH+1);
- while(fgets(line, sizeof(line), fp))
- {
- line_num++;
- if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
- continue;
+ RFIFOSKIP(fd,6);
- if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4)
- {
- ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
- continue;
+ if( !accounts->load_num(accounts, &acc, account_id) )
+ ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip);
+ else{
+ struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data;
+ safestrncpy(email, acc.email, sizeof(email));
+ expiration_time = acc.expiration_time;
+ group_id = acc.group_id;
+ char_slots = acc.char_slots;
+ safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
+ safestrncpy(pincode, acc.pincode, sizeof(pincode));
+ if(sd) cl_version = sd->version;
+ ShowInfo("login R_0x2716, S_0x2717 version = %d, sd=%d\n",cl_version,sd);
}
- if( strcmpi(w1, "subnet") == 0 )
- {
- subnet[subnet_count].mask = str2ip(w2);
- subnet[subnet_count].char_ip = str2ip(w3);
- subnet[subnet_count].map_ip = str2ip(w4);
-
- if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
- {
- ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
- continue;
- }
-
- subnet_count++;
- }
+ WFIFOHEAD(fd,73);
+ WFIFOW(fd,0) = 0x2717;
+ WFIFOL(fd,2) = account_id;
+ safestrncpy((char*)WFIFOP(fd,6), email, 40);
+ WFIFOL(fd,46) = (uint32)expiration_time;
+ WFIFOB(fd,50) = (unsigned char)group_id;
+ WFIFOB(fd,51) = char_slots;
+ safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
+ safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
+ WFIFOL(fd,68) = (uint32)acc.pincode_change;
+ WFIFOB(fd,72) = cl_version;
+ WFIFOSET(fd,73);
}
+ return 1;
+}
- if( subnet_count > 1 ) /* only useful if there is more than 1 available */
- ShowStatus("Read information about %d subnetworks.\n", subnet_count);
-
- fclose(fp);
- return 0;
+int login_parsechar_keepalive(int fd){
+ RFIFOSKIP(fd,2);
+ WFIFOHEAD(fd,2);
+ WFIFOW(fd,0) = 0x2718;
+ WFIFOSET(fd,2);
+ return 1;
}
-//-----------------------
-// Console Command Parser [Wizputer]
-//-----------------------
-int parse_console(const char* buf){
- char type[64];
- char command[64];
- int n=0;
+// 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
+int login_parsechar_reqchangemail(int fd, int id, char* ip){
+ if (RFIFOREST(fd) < 86)
+ return 0;
+ else{
+ struct mmo_account acc;
+ char actual_email[40];
+ char new_email[40];
- if( ( n = sscanf(buf, "%127[^:]:%255[^\n\r]", type, command) ) < 2 ){
- if((n = sscanf(buf, "%63[^\n]", type))<1) return -1; //nothing to do no arg
- }
- if( n != 2 ){ //end string
- ShowNotice("Type: '%s'\n",type);
- command[0] = '\0';
- }
- else
- ShowNotice("Type of command: '%s' || Command: '%s'\n",type,command);
+ int account_id = RFIFOL(fd,2);
+ safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40);
+ safestrncpy(new_email, (char*)RFIFOP(fd,46), 40);
+ RFIFOSKIP(fd, 86);
- if( n == 2 ){
- if(strcmpi("server", type) == 0 ){
- if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 ){
- runflag = 0;
- }
- else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 )
- ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n");
+ if( e_mail_check(actual_email) == 0 )
+ ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip);
+ else if( e_mail_check(new_email) == 0 )
+ ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip);
+ else if( strcmpi(new_email, "[email protected]") == 0 )
+ ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip);
+ else if( !accounts->load_num(accounts, &acc, account_id) )
+ ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip);
+ else if( strcmpi(acc.email, actual_email) != 0 )
+ ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip);
+ else{
+ safestrncpy(acc.email, new_email, 40);
+ ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip);
+ // Save
+ accounts->save(accounts, &acc);
}
- if( strcmpi("create",type) == 0 )
- {
- char username[NAME_LENGTH], password[NAME_LENGTH], md5password[32+1], sex; //23+1 plaintext 32+1 md5
- bool md5 = 0;
- if( sscanf(command, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ){
- ShowWarning("Console: Invalid parameters for '%s'. Usage: %s <username> <password> <sex:F/M>\n", type, type);
- return 0;
- }
- if( login_config.use_md5_passwds ){
- MD5_String(password,md5password);
- md5 = 1;
- }
- if( mmo_auth_new(username,(md5?md5password:password), TOUPPER(sex), "0.0.0.0") != -1 ){
- ShowError("Console: Account creation failed.\n");
- return 0;
- }
- ShowStatus("Console: Account '%s' created successfully.\n", username);
- }
}
- else if( strcmpi("ers_report", type) == 0 ){
- ers_report();
- }
- else if( strcmpi("help", type) == 0 ){
- ShowInfo("Available commands:\n");
- ShowInfo("\t server:shutdown => Stops the server.\n");
- ShowInfo("\t server:alive => Checks if the server is running.\n");
- ShowInfo("\t ers_report => Displays database usage.\n");
- ShowInfo("\t create:<username> <password> <sex:M|F> => Creates a new account.\n");
- }
- else{ // commands with parameters
-
-
-
- }
-
- return 0;
+ return 1;
}
-
-//--------------------------------
-// Packet parsing for char-servers
-//--------------------------------
-int parse_fromchar(int fd){
- int j, id;
- uint32 ipl;
- char ip[16];
-
- ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
- if( id == ARRAYLENGTH(server) ){// not a char server
- ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd);
- set_eof(fd);
- do_close(fd);
+int login_parsechar_requpdaccstate(int fd, int id, char* ip){
+ if (RFIFOREST(fd) < 10)
return 0;
- }
+ else{
+ struct mmo_account acc;
- if( session[fd]->flag.eof ){
- do_close(fd);
- server[id].fd = -1;
- chrif_on_disconnect(id);
- return 0;
- }
+ int account_id = RFIFOL(fd,2);
+ unsigned int state = RFIFOL(fd,6);
+ RFIFOSKIP(fd,10);
- ipl = server[id].ip;
- ip2str(ipl, ip);
+ if( !accounts->load_num(accounts, &acc, account_id) )
+ ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip);
+ else if( acc.state == state )
+ ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip);
+ else{
+ ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip);
- while( RFIFOREST(fd) >= 2 ){
- uint16 command = RFIFOW(fd,0);
+ acc.state = state;
+ // Save
+ accounts->save(accounts, &acc);
- switch( command ){
-
- case 0x2712: // request from char-server to authenticate an account
- if( RFIFOREST(fd) < 23 )
- return 0;
- else{
- struct auth_node* node;
- int account_id = RFIFOL(fd,2);
- uint32 login_id1 = RFIFOL(fd,6);
- uint32 login_id2 = RFIFOL(fd,10);
- uint8 sex = RFIFOB(fd,14);
- //uint32 ip_ = ntohl(RFIFOL(fd,15));
- int request_id = RFIFOL(fd,19);
- RFIFOSKIP(fd,23);
-
- node = (struct auth_node*)idb_get(auth_db, account_id);
- if( runflag == LOGINSERVER_ST_RUNNING &&
- node != NULL &&
- node->account_id == account_id &&
- node->login_id1 == login_id1 &&
- node->login_id2 == login_id2 &&
- node->sex == sex_num2str(sex) /*&&
- node->ip == ip_*/ ){// found
- //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip);
-
- // send ack
- WFIFOHEAD(fd,25);
- WFIFOW(fd,0) = 0x2713;
- WFIFOL(fd,2) = account_id;
- WFIFOL(fd,6) = login_id1;
- WFIFOL(fd,10) = login_id2;
- WFIFOB(fd,14) = sex;
- WFIFOB(fd,15) = 0;// ok
- WFIFOL(fd,16) = request_id;
- WFIFOL(fd,20) = node->version;
- WFIFOB(fd,24) = node->clienttype;
- WFIFOSET(fd,25);
-
- // each auth entry can only be used once
- idb_remove(auth_db, account_id);
- }else{// authentication not found
- ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip);
- WFIFOHEAD(fd,25);
- WFIFOW(fd,0) = 0x2713;
- WFIFOL(fd,2) = account_id;
- WFIFOL(fd,6) = login_id1;
- WFIFOL(fd,10) = login_id2;
- WFIFOB(fd,14) = sex;
- WFIFOB(fd,15) = 1;// auth failed
- WFIFOL(fd,16) = request_id;
- WFIFOL(fd,20) = 0;
- WFIFOB(fd,24) = 0;
- WFIFOSET(fd,25);
- }
+ // notify other servers
+ if (state != 0){
+ uint8 buf[11];
+ WBUFW(buf,0) = 0x2731;
+ WBUFL(buf,2) = account_id;
+ WBUFB(buf,6) = 0; // 0: change of state, 1: ban
+ WBUFL(buf,7) = state; // status or final date of a banishment
+ charif_sendallwos(-1, buf, 11);
}
- break;
+ }
+ }
+ return 1;
+}
- case 0x2714:
- if( RFIFOREST(fd) < 6 )
- return 0;
- else{
- int users = RFIFOL(fd,2);
- RFIFOSKIP(fd,6);
+int login_parsechar_reqbanacc(int fd, int id, char* ip){
+ if (RFIFOREST(fd) < 18)
+ return 0;
+ else{
+ struct mmo_account acc;
- // how many users on world? (update)
- if( server[id].users != users ){
- ShowStatus("set users %s : %d\n", server[id].name, users);
+ int account_id = RFIFOL(fd,2);
+ int year = (short)RFIFOW(fd,6);
+ int month = (short)RFIFOW(fd,8);
+ int mday = (short)RFIFOW(fd,10);
+ int hour = (short)RFIFOW(fd,12);
+ int min = (short)RFIFOW(fd,14);
+ int sec = (short)RFIFOW(fd,16);
+ RFIFOSKIP(fd,18);
- server[id].users = users;
- }
- }
- break;
-
- case 0x2715: // request from char server to change e-email from default "[email protected]"
- if (RFIFOREST(fd) < 46)
- return 0;
+ if( !accounts->load_num(accounts, &acc, account_id) )
+ ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
+ else{
+ time_t timestamp;
+ struct tm *tmtime;
+ if (acc.unban_time == 0 || acc.unban_time < time(NULL))
+ timestamp = time(NULL); // new ban
+ else
+ timestamp = acc.unban_time; // add to existing ban
+ tmtime = localtime(×tamp);
+ tmtime->tm_year = tmtime->tm_year + year;
+ tmtime->tm_mon = tmtime->tm_mon + month;
+ tmtime->tm_mday = tmtime->tm_mday + mday;
+ tmtime->tm_hour = tmtime->tm_hour + hour;
+ tmtime->tm_min = tmtime->tm_min + min;
+ tmtime->tm_sec = tmtime->tm_sec + sec;
+ timestamp = mktime(tmtime);
+ if (timestamp == -1)
+ ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip);
+ else if( timestamp <= time(NULL) || timestamp == 0 )
+ ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip);
else{
- struct mmo_account acc;
- char email[40];
+ uint8 buf[11];
+ char tmpstr[24];
+ timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format);
+ ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip);
- int account_id = RFIFOL(fd,2);
- safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email);
- RFIFOSKIP(fd,46);
+ acc.unban_time = timestamp;
- if( e_mail_check(email) == 0 )
- ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip);
- else if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "[email protected]") == 0 || acc.email[0] == '\0' )
- ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip);
- else{
- memcpy(acc.email, email, 40);
- ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip);
- // Save
- accounts->save(accounts, &acc);
- }
- }
- break;
+ // Save
+ accounts->save(accounts, &acc);
- case 0x2716: // request account data
- if( RFIFOREST(fd) < 6 )
- return 0;
- else{
- struct mmo_account acc;
- time_t expiration_time = 0;
- char email[40] = "";
- uint8 char_slots = 0;
- int group_id = 0;
- char birthdate[10+1] = "";
- char pincode[PINCODE_LENGTH+1];
- int account_id = RFIFOL(fd,2);
-
- memset(pincode,0,PINCODE_LENGTH+1);
-
- RFIFOSKIP(fd,6);
-
- if( !accounts->load_num(accounts, &acc, account_id) )
- ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip);
- else{
- safestrncpy(email, acc.email, sizeof(email));
- expiration_time = acc.expiration_time;
- group_id = acc.group_id;
- char_slots = acc.char_slots;
- safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
- safestrncpy(pincode, acc.pincode, sizeof(pincode));
- }
-
- WFIFOHEAD(fd,72);
- WFIFOW(fd,0) = 0x2717;
- WFIFOL(fd,2) = account_id;
- safestrncpy((char*)WFIFOP(fd,6), email, 40);
- WFIFOL(fd,46) = (uint32)expiration_time;
- WFIFOB(fd,50) = (unsigned char)group_id;
- WFIFOB(fd,51) = char_slots;
- safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
- safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
- WFIFOL(fd,68) = (uint32)acc.pincode_change;
- WFIFOSET(fd,72);
+ WBUFW(buf,0) = 0x2731;
+ WBUFL(buf,2) = account_id;
+ WBUFB(buf,6) = 1; // 0: change of status, 1: ban
+ WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment
+ charif_sendallwos(-1, buf, 11);
}
- break;
+ }
+ }
+ return 1;
+}
- case 0x2719: // ping request from charserver
- RFIFOSKIP(fd,2);
+int login_parsechar_reqchgsex(int fd, int id, char* ip){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ else{
+ struct mmo_account acc;
- WFIFOHEAD(fd,2);
- WFIFOW(fd,0) = 0x2718;
- WFIFOSET(fd,2);
- break;
+ int account_id = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
- // Map server send information to change an email of an account via char-server
- case 0x2722: // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
- if (RFIFOREST(fd) < 86)
- return 0;
- else{
- struct mmo_account acc;
- char actual_email[40];
- char new_email[40];
+ if( !accounts->load_num(accounts, &acc, account_id) )
+ ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
+ else if( acc.sex == 'S' )
+ ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip);
+ else{
+ unsigned char buf[7];
+ char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender
- int account_id = RFIFOL(fd,2);
- safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40);
- safestrncpy(new_email, (char*)RFIFOP(fd,46), 40);
- RFIFOSKIP(fd, 86);
+ ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip);
- if( e_mail_check(actual_email) == 0 )
- ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip);
- else if( e_mail_check(new_email) == 0 )
- ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip);
- else if( strcmpi(new_email, "[email protected]") == 0 )
- ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip);
- else if( !accounts->load_num(accounts, &acc, account_id) )
- ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip);
- else if( strcmpi(acc.email, actual_email) != 0 )
- ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip);
- else{
- safestrncpy(acc.email, new_email, 40);
- ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip);
- // Save
- accounts->save(accounts, &acc);
- }
- }
- break;
+ acc.sex = sex;
+ // Save
+ accounts->save(accounts, &acc);
- case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server)
- if (RFIFOREST(fd) < 10)
- return 0;
- else{
- struct mmo_account acc;
+ // announce to other servers
+ WBUFW(buf,0) = 0x2723;
+ WBUFL(buf,2) = account_id;
+ WBUFB(buf,6) = sex_str2num(sex);
+ charif_sendallwos(-1, buf, 7);
+ }
+ }
+ return 1;
+}
- int account_id = RFIFOL(fd,2);
- unsigned int state = RFIFOL(fd,6);
- RFIFOSKIP(fd,10);
+int login_parsechar_updreg2(int fd, int id, char* ip){
+ int j;
+ if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) )
+ return 0;
+ else{
+ struct mmo_account acc;
- if( !accounts->load_num(accounts, &acc, account_id) )
- ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip);
- else if( acc.state == state )
- ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip);
- else{
- ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip);
+ int account_id = RFIFOL(fd,4);
- acc.state = state;
- // Save
- accounts->save(accounts, &acc);
-
- // notify other servers
- if (state != 0){
- uint8 buf[11];
- WBUFW(buf,0) = 0x2731;
- WBUFL(buf,2) = account_id;
- WBUFB(buf,6) = 0; // 0: change of state, 1: ban
- WBUFL(buf,7) = state; // status or final date of a banishment
- charif_sendallwos(-1, buf, 11);
- }
- }
+ if( !accounts->load_num(accounts, &acc, account_id) )
+ ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
+ else{
+ int len;
+ int p;
+ ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip);
+ for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ){
+ sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len);
+ acc.account_reg2[j].str[len]='\0';
+ p +=len+1; //+1 to skip the '\0' between strings.
+ sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len);
+ acc.account_reg2[j].value[len]='\0';
+ p +=len+1;
+ remove_control_chars(acc.account_reg2[j].str);
+ remove_control_chars(acc.account_reg2[j].value);
}
- break;
+ acc.account_reg2_num = j;
- case 0x2725: // Receiving of map-server via char-server a ban request
- if (RFIFOREST(fd) < 18)
- return 0;
- else{
- struct mmo_account acc;
+ // Save
+ accounts->save(accounts, &acc);
- int account_id = RFIFOL(fd,2);
- int year = (short)RFIFOW(fd,6);
- int month = (short)RFIFOW(fd,8);
- int mday = (short)RFIFOW(fd,10);
- int hour = (short)RFIFOW(fd,12);
- int min = (short)RFIFOW(fd,14);
- int sec = (short)RFIFOW(fd,16);
- RFIFOSKIP(fd,18);
+ // Sending information towards the other char-servers.
+ RFIFOW(fd,0) = 0x2729;// reusing read buffer
+ charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2));
+ }
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ }
+ return 1;
+}
- if( !accounts->load_num(accounts, &acc, account_id) )
- ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
- else{
- time_t timestamp;
- struct tm *tmtime;
- if (acc.unban_time == 0 || acc.unban_time < time(NULL))
- timestamp = time(NULL); // new ban
- else
- timestamp = acc.unban_time; // add to existing ban
- tmtime = localtime(×tamp);
- tmtime->tm_year = tmtime->tm_year + year;
- tmtime->tm_mon = tmtime->tm_mon + month;
- tmtime->tm_mday = tmtime->tm_mday + mday;
- tmtime->tm_hour = tmtime->tm_hour + hour;
- tmtime->tm_min = tmtime->tm_min + min;
- tmtime->tm_sec = tmtime->tm_sec + sec;
- timestamp = mktime(tmtime);
- if (timestamp == -1)
- ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip);
- else if( timestamp <= time(NULL) || timestamp == 0 )
- ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip);
- else{
- uint8 buf[11];
- char tmpstr[24];
- timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format);
- ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip);
+int login_parsechar_requnbanacc(int fd, int id, char* ip){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ else{
+ struct mmo_account acc;
- acc.unban_time = timestamp;
+ int account_id = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
- // Save
- accounts->save(accounts, &acc);
+ if( !accounts->load_num(accounts, &acc, account_id) )
+ ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
+ else if( acc.unban_time == 0 )
+ ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip);
+ else{
+ ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip);
+ acc.unban_time = 0;
+ accounts->save(accounts, &acc);
+ }
+ }
+ return 1;
+}
- WBUFW(buf,0) = 0x2731;
- WBUFL(buf,2) = account_id;
- WBUFB(buf,6) = 1; // 0: change of status, 1: ban
- WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment
- charif_sendallwos(-1, buf, 11);
- }
- }
- }
- break;
+int login_parsechar_setacconline(int fd, int id){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ add_online_user(id, RFIFOL(fd,2));
+ RFIFOSKIP(fd,6);
+ return 1;
+}
- case 0x2727: // Change of sex (sex is reversed)
- if( RFIFOREST(fd) < 6 )
- return 0;
- else{
- struct mmo_account acc;
+int login_parsechar_setaccoffline(int fd, int id){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ remove_online_user(RFIFOL(fd,2));
+ RFIFOSKIP(fd,6);
+ return 1;
+}
- int account_id = RFIFOL(fd,2);
- RFIFOSKIP(fd,6);
-
- if( !accounts->load_num(accounts, &acc, account_id) )
- ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
- else if( acc.sex == 'S' )
- ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip);
- else{
- unsigned char buf[7];
- char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender
-
- ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip);
-
- acc.sex = sex;
- // Save
- accounts->save(accounts, &acc);
-
- // announce to other servers
- WBUFW(buf,0) = 0x2723;
- WBUFL(buf,2) = account_id;
- WBUFB(buf,6) = sex_str2num(sex);
- charif_sendallwos(-1, buf, 7);
- }
+int login_parsechar_updonlinedb(int fd, int id){
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ else{
+ struct online_login_data *p;
+ int aid;
+ uint32 i, users;
+ online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first
+ users = RFIFOW(fd,4);
+ for (i = 0; i < users; i++) {
+ aid = RFIFOL(fd,6+i*4);
+ p = idb_ensure(online_db, aid, create_online_user);
+ p->char_server = id;
+ if (p->waiting_disconnect != INVALID_TIMER){
+ delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
+ p->waiting_disconnect = INVALID_TIMER;
}
- break;
+ }
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ }
+ return 1;
+}
- case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers.
- if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) )
- return 0;
- else{
- struct mmo_account acc;
+int login_parsechar_reqacc2reg(int fd, int id){
+ int j;
+ if (RFIFOREST(fd) < 10)
+ return 0;
+ else{
+ struct mmo_account acc;
+ size_t off;
- int account_id = RFIFOL(fd,4);
+ int account_id = RFIFOL(fd,2);
+ int char_id = RFIFOL(fd,6);
+ RFIFOSKIP(fd,10);
- if( !accounts->load_num(accounts, &acc, account_id) )
- ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
- else{
- int len;
- int p;
- ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip);
- for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ){
- sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len);
- acc.account_reg2[j].str[len]='\0';
- p +=len+1; //+1 to skip the '\0' between strings.
- sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len);
- acc.account_reg2[j].value[len]='\0';
- p +=len+1;
- remove_control_chars(acc.account_reg2[j].str);
- remove_control_chars(acc.account_reg2[j].value);
- }
- acc.account_reg2_num = j;
+ WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg));
+ WFIFOW(fd,0) = 0x2729;
+ WFIFOL(fd,4) = account_id;
+ WFIFOL(fd,8) = char_id;
+ WFIFOB(fd,12) = 1; //Type 1 for Account2 registry
- // Save
- accounts->save(accounts, &acc);
-
- // Sending information towards the other char-servers.
- RFIFOW(fd,0) = 0x2729;// reusing read buffer
- charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2));
+ off = 13;
+ if( accounts->load_num(accounts, &acc, account_id) ){
+ for( j = 0; j < acc.account_reg2_num; j++ ){
+ if( acc.account_reg2[j].str[0] != '\0' ){
+ off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place.
+ off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1;
}
- RFIFOSKIP(fd,RFIFOW(fd,2));
}
- break;
+ }
- case 0x272a: // Receiving of map-server via char-server an unban request
- if( RFIFOREST(fd) < 6 )
- return 0;
- else{
- struct mmo_account acc;
+ WFIFOW(fd,2) = (uint16)off;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 1;
+}
- int account_id = RFIFOL(fd,2);
- RFIFOSKIP(fd,6);
+int login_parsechar_updcharip(int fd, int id){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ server[id].ip = ntohl(RFIFOL(fd,2));
+ ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip));
+ RFIFOSKIP(fd,6);
+ return 1;
+}
- if( !accounts->load_num(accounts, &acc, account_id) )
- ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
- else if( acc.unban_time == 0 )
- ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip);
- else{
- ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip);
- acc.unban_time = 0;
- accounts->save(accounts, &acc);
- }
- }
- break;
+int login_parsechar_setalloffline(int fd, int id){
+ ShowInfo("Setting accounts from char-server %d offline.\n", id);
+ online_db->foreach(online_db, online_db_setoffline, id);
+ RFIFOSKIP(fd,2);
+ return 1;
+}
- case 0x272b: // Set account_id to online [Wizputer]
- if( RFIFOREST(fd) < 6 )
- return 0;
- add_online_user(id, RFIFOL(fd,2));
- RFIFOSKIP(fd,6);
- break;
+int login_parsechar_updpincode(int fd, int id){
+ if( RFIFOREST(fd) < 11 )
+ return 0;
+ else{
+ struct mmo_account acc;
- case 0x272c: // Set account_id to offline [Wizputer]
- if( RFIFOREST(fd) < 6 )
- return 0;
- remove_online_user(RFIFOL(fd,2));
- RFIFOSKIP(fd,6);
- break;
+ if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
+ strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 );
+ acc.pincode_change = time( NULL );
+ accounts->save(accounts, &acc);
+ }
- case 0x272d: // Receive list of all online accounts. [Skotlex]
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- else{
- struct online_login_data *p;
- int aid;
- uint32 i, users;
- online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first
- users = RFIFOW(fd,4);
- for (i = 0; i < users; i++) {
- aid = RFIFOL(fd,6+i*4);
- p = idb_ensure(online_db, aid, create_online_user);
- p->char_server = id;
- if (p->waiting_disconnect != INVALID_TIMER){
- delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
- p->waiting_disconnect = INVALID_TIMER;
- }
- }
+ RFIFOSKIP(fd,11);
+ }
+ return 1;
+}
- RFIFOSKIP(fd,RFIFOW(fd,2));
- }
- break;
+int login_parsechar_pincode_authfail(int fd, int id){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ else{
+ struct mmo_account acc;
+ if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
+ struct online_login_data* ld;
- case 0x272e: //Request account_reg2 for a character.
- if (RFIFOREST(fd) < 10)
- return 0;
- else{
- struct mmo_account acc;
- size_t off;
+ ld = (struct online_login_data*)idb_get(online_db,acc.account_id);
- int account_id = RFIFOL(fd,2);
- int char_id = RFIFOL(fd,6);
- RFIFOSKIP(fd,10);
-
- WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg));
- WFIFOW(fd,0) = 0x2729;
- WFIFOL(fd,4) = account_id;
- WFIFOL(fd,8) = char_id;
- WFIFOB(fd,12) = 1; //Type 1 for Account2 registry
-
- off = 13;
- if( accounts->load_num(accounts, &acc, account_id) ){
- for( j = 0; j < acc.account_reg2_num; j++ ){
- if( acc.account_reg2[j].str[0] != '\0' ){
- off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place.
- off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1;
- }
- }
- }
-
- WFIFOW(fd,2) = (uint16)off;
- WFIFOSET(fd,WFIFOW(fd,2));
- }
- break;
-
- case 0x2736: // WAN IP update from char-server
- if( RFIFOREST(fd) < 6 )
+ if( ld == NULL )
return 0;
- server[id].ip = ntohl(RFIFOL(fd,2));
- ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip));
- RFIFOSKIP(fd,6);
- break;
- case 0x2737: //Request to set all offline.
- ShowInfo("Setting accounts from char-server %d offline.\n", id);
- online_db->foreach(online_db, online_db_setoffline, id);
- RFIFOSKIP(fd,2);
- break;
+ login_log( host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed" );
+ }
+ remove_online_user(acc.account_id);
+ RFIFOSKIP(fd,6);
+ }
+ return 1;
+}
- case 0x2738: //Change PIN Code for a account
- if( RFIFOREST(fd) < 11 )
- return 0;
- else{
- struct mmo_account acc;
+//--------------------------------
+// Packet parsing for char-servers
+//--------------------------------
+int parse_fromchar(int fd){
+ int id;
+ uint32 ipl;
+ char ip[16];
- if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
- strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 );
- acc.pincode_change = time( NULL );
- accounts->save(accounts, &acc);
- }
+ ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
+ if( id == ARRAYLENGTH(server) ){// not a char server
+ ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd);
+ set_eof(fd);
+ do_close(fd);
+ return 0;
+ }
- RFIFOSKIP(fd,11);
- }
- break;
+ if( session[fd]->flag.eof ){
+ do_close(fd);
+ server[id].fd = -1;
+ chrif_on_disconnect(id);
+ return 0;
+ }
- case 0x2739: // PIN Code was entered wrong too often
- if( RFIFOREST(fd) < 6 )
- return 0;
- else{
- struct mmo_account acc;
+ ipl = server[id].ip;
+ ip2str(ipl, ip);
- if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
- struct online_login_data* ld;
+ while( RFIFOREST(fd) >= 2 ){
+ uint16 command = RFIFOW(fd,0);
- ld = (struct online_login_data*)idb_get(online_db,acc.account_id);
-
- if( ld == NULL )
- return 0;
-
- login_log( host2ip(acc.last_ip), acc.userid, 100, "PIN Code check failed" );
- }
-
- remove_online_user(acc.account_id);
-
- RFIFOSKIP(fd,6);
- }
- break;
-
+ switch( command ){
+ // request from char-server to authenticate an account
+ case 0x2712: login_parsechar_reqauth(fd, id, ip); break;
+ //update user cout
+ case 0x2714: login_parsechar_ackusercount(fd, id); break;
+ // request from char server to change e-email from default "[email protected]"
+ case 0x2715: login_parsechar_updmail(fd, id, ip); break;
+ // request account data
+ case 0x2716: login_parsechar_reqaccdata(fd, id, ip); break;
+ // ping request from charserver
+ case 0x2719: login_parsechar_keepalive(fd); break;
+ // Map server send information to change an email of an account via char-server
+ case 0x2722: login_parsechar_reqchangemail(fd,id,ip); break;
+ // Receiving an account state update request from a map-server (relayed via char-server)
+ case 0x2724: login_parsechar_requpdaccstate(fd,id,ip); break;
+ // Receiving of map-server via char-server a ban request
+ case 0x2725: login_parsechar_reqbanacc(fd,id,ip); break;
+ // Change of sex (sex is reversed)
+ case 0x2727: login_parsechar_reqchgsex(fd,id,ip); break;
+ // We receive account_reg2 from a char-server, and we send them to other map-servers.
+ case 0x2728: login_parsechar_updreg2(fd,id,ip); break;
+ // Receiving of map-server via char-server an unban request
+ case 0x272a: login_parsechar_requnbanacc(fd,id,ip); break;
+ // Set account_id to online [Wizputer]
+ case 0x272b: login_parsechar_setacconline(fd,id); break;
+ // Set account_id to offline [Wizputer]
+ case 0x272c: login_parsechar_setaccoffline(fd,id); break;
+ // Receive list of all online accounts. [Skotlex]
+ case 0x272d: login_parsechar_updonlinedb(fd,id); break;
+ //Request account_reg2 for a character
+ case 0x272e: login_parsechar_reqacc2reg(fd,id); break;
+ // WAN IP update from char-server
+ case 0x2736: login_parsechar_updcharip(fd,id); break;
+ //Request to set all offline.
+ case 0x2737: login_parsechar_setalloffline(fd,id); break;
+ //Change PIN Code for a account
+ case 0x2738: login_parsechar_updpincode(fd,id); break;
+ // PIN Code was entered wrong too often
+ case 0x2739: login_parsechar_pincode_authfail(fd,id); break;
default:
ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
set_eof(fd);
@@ -952,6 +918,39 @@
}
+///
+/// Client IF
+///
+
+//-----------------------------------------------------
+// encrypted/unencrypted password check (from eApp)
+//-----------------------------------------------------
+bool check_encrypted(const char* str1, const char* str2, const char* passwd)
+{
+ char tmpstr[64+1], md5str[32+1];
+
+ safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
+ MD5_String(tmpstr, md5str);
+
+ return (0==strcmp(passwd, md5str));
+}
+
+bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass)
+{
+ if(passwdenc == 0)
+ {
+ return (0==strcmp(passwd, refpass));
+ }
+ else
+ {
+ // password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
+ // password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
+
+ return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) ||
+ ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd));
+ }
+}
+
//-------------------------------------
// Make new account
//-------------------------------------
@@ -1101,7 +1100,9 @@
}
while( node ) {
- if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) {
+ ShowInfo("login mmo_auth, node_groupid=%d, acc_groupid=%d node_hash=%s client_hash=%d\n",
+ node->group_id,acc.group_id,node->hash,sd->client_hash);
+ if( node->group_id <= acc.group_id && (memcmp(node->hash, sd->client_hash, 16) == 0 || strcmp(node->hash,"any")==0 ) ){
match = true;
break;
}
@@ -1270,10 +1271,8 @@
{
struct online_login_data* data;
-
// mark client as 'online'
data = add_online_user(-1, sd->account_id);
-
// schedule deletion of this node
data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0);
}
@@ -1323,108 +1322,61 @@
if( result == 1 && login_config.dynamic_pass_failure_ban )
ipban_log(ip); // log failed password attempt
-#if PACKETVER >= 20120000 /* not sure when this started */
- WFIFOHEAD(fd,26);
- WFIFOW(fd,0) = 0x83e;
- WFIFOL(fd,2) = result;
- if( result != 6 )
- memset(WFIFOP(fd,6), '\0', 20);
- else { // 6 = Your are Prohibited to log in until %s
- struct mmo_account acc;
- time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
- timestamp2string((char*)WFIFOP(fd,6), 20, unban_time, login_config.date_format);
+ if( sd->version >= date2version(20120000) ){ /* not sure when this started */
+ WFIFOHEAD(fd,26);
+ WFIFOW(fd,0) = 0x83e;
+ WFIFOL(fd,2) = result;
+ if( result != 6 )
+ memset(WFIFOP(fd,6), '\0', 20);
+ else { // 6 = Your are Prohibited to log in until %s
+ struct mmo_account acc;
+ time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
+ timestamp2string((char*)WFIFOP(fd,6), 20, unban_time, login_config.date_format);
+ }
+ WFIFOSET(fd,26);
}
- WFIFOSET(fd,26);
-#else
- WFIFOHEAD(fd,23);
- WFIFOW(fd,0) = 0x6a;
- WFIFOB(fd,2) = (uint8)result;
- if( result != 6 )
- memset(WFIFOP(fd,3), '\0', 20);
- else { // 6 = Your are Prohibited to log in until %s
- struct mmo_account acc;
- time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
- timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format);
+ else {
+ WFIFOHEAD(fd,23);
+ WFIFOW(fd,0) = 0x6a;
+ WFIFOB(fd,2) = (uint8)result;
+ if( result != 6 )
+ memset(WFIFOP(fd,3), '\0', 20);
+ else { // 6 = Your are Prohibited to log in until %s
+ struct mmo_account acc;
+ time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
+ timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format);
+ }
+ WFIFOSET(fd,23);
}
- WFIFOSET(fd,23);
-#endif
}
+//0x200 <account.userid>.24B.
+int login_parse_keepalive(int fd){
+ if (RFIFOREST(fd) < 26)
+ return 0;
+ RFIFOSKIP(fd,26);
+ return 1;
+}
-//----------------------------------------------------------------------------------------
-// Default packet parsing (normal players or char-server connection requests)
-//----------------------------------------------------------------------------------------
-int parse_login(int fd)
-{
- struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data;
- int result;
-
- char ip[16];
- uint32 ipl = session[fd]->client_addr;
- ip2str(ipl, ip);
-
- if( session[fd]->flag.eof )
- {
- ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip);
- do_close(fd);
+// S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6)
+int login_parse_updclhash(int fd, struct login_session_data *sd){
+ if (RFIFOREST(fd) < 18)
return 0;
- }
+ sd->has_client_hash = 1;
+ memcpy(sd->client_hash, RFIFOP(fd, 2), 16);
+ RFIFOSKIP(fd,18);
+ return 1;
+}
- if( sd == NULL )
- {
- // Perform ip-ban check
- if( login_config.ipban && ipban_check(ipl) )
+// S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
+// S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
+// S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
+// S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
+// S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
+// S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
+// S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
+int login_parse_reqauth(int fd, struct login_session_data *sd, int command, char* ip){
{
- ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip);
- login_log(ipl, "unknown", -3, "ip banned");
- WFIFOHEAD(fd,23);
- WFIFOW(fd,0) = 0x6a;
- WFIFOB(fd,2) = 3; // 3 = Rejected from Server
- WFIFOSET(fd,23);
- set_eof(fd);
- return 0;
- }
-
- // create a session for this new connection
- CREATE(session[fd]->session_data, struct login_session_data, 1);
- sd = (struct login_session_data*)session[fd]->session_data;
- sd->fd = fd;
- }
-
- while( RFIFOREST(fd) >= 2 )
- {
- uint16 command = RFIFOW(fd,0);
-
- switch( command )
- {
-
- case 0x0200: // New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
- if (RFIFOREST(fd) < 26)
- return 0;
- RFIFOSKIP(fd,26);
- break;
-
- // client md5 hash (binary)
- case 0x0204: // S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6)
- if (RFIFOREST(fd) < 18)
- return 0;
-
- sd->has_client_hash = 1;
- memcpy(sd->client_hash, RFIFOP(fd, 2), 16);
-
- RFIFOSKIP(fd,18);
- break;
-
- // request client login (raw password)
- case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
- case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
- case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
- // request client login (md5-hashed password)
- case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
- case 0x01fa: // S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
- case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
- case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
- {
size_t packet_len = RFIFOREST(fd);
if( (command == 0x0064 && packet_len < 55)
@@ -1437,6 +1389,7 @@
return 0;
}
{
+ int result;
uint32 version;
char username[NAME_LENGTH];
char password[NAME_LENGTH];
@@ -1512,88 +1465,156 @@
else
login_auth_failed(sd, result);
}
- break;
+ return 1;
+}
- case 0x01db: // Sending request of the coding key
- RFIFOSKIP(fd,2);
+int login_parse_reqkey(int fd, struct login_session_data *sd){
+ RFIFOSKIP(fd,2);
+ {
+ memset(sd->md5key, '\0', sizeof(sd->md5key));
+ sd->md5keylen = (uint16)(12 + rnd() % 4);
+ MD5_Salt(sd->md5keylen, sd->md5key);
+
+ WFIFOHEAD(fd,4 + sd->md5keylen);
+ WFIFOW(fd,0) = 0x01dc;
+ WFIFOW(fd,2) = 4 + sd->md5keylen;
+ memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen);
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 1;
+}
+
+int login_parse_reqcharconnec(int fd, struct login_session_data *sd, char* ip){
+ if (RFIFOREST(fd) < 86)
+ return 0;
+ {
+ int result;
+ char server_name[20];
+ char message[256];
+ uint32 server_ip;
+ uint16 server_port;
+ uint16 type;
+ uint16 new_;
+
+ safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH);
+ safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH);
+ if( login_config.use_md5_passwds )
+ MD5_String(sd->passwd, sd->passwd);
+ sd->passwdenc = 0;
+ sd->version = login_config.client_version_to_connect; // hack to skip version check
+ server_ip = ntohl(RFIFOL(fd,54));
+ server_port = ntohs(RFIFOW(fd,58));
+ safestrncpy(server_name, (char*)RFIFOP(fd,60), 20);
+ type = RFIFOW(fd,82);
+ new_ = RFIFOW(fd,84);
+ RFIFOSKIP(fd,86);
+
+ ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip);
+ sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port);
+ login_log(session[fd]->client_addr, sd->userid, 100, message);
+
+ result = mmo_auth(sd, true);
+ if( runflag == LOGINSERVER_ST_RUNNING &&
+ result == -1 &&
+ sd->sex == 'S' &&
+ sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) &&
+ !session_isValid(server[sd->account_id].fd) )
{
- memset(sd->md5key, '\0', sizeof(sd->md5key));
- sd->md5keylen = (uint16)(12 + rnd() % 4);
- MD5_Salt(sd->md5keylen, sd->md5key);
+ ShowStatus("Connection of the char-server '%s' accepted.\n", server_name);
+ safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name));
+ server[sd->account_id].fd = fd;
+ server[sd->account_id].ip = server_ip;
+ server[sd->account_id].port = server_port;
+ server[sd->account_id].users = 0;
+ server[sd->account_id].type = type;
+ server[sd->account_id].new_ = new_;
- WFIFOHEAD(fd,4 + sd->md5keylen);
- WFIFOW(fd,0) = 0x01dc;
- WFIFOW(fd,2) = 4 + sd->md5keylen;
- memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen);
- WFIFOSET(fd,WFIFOW(fd,2));
+ session[fd]->func_parse = parse_fromchar;
+ session[fd]->flag.server = 1;
+ realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
+
+ // send connection success
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x2711;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
}
- break;
-
- case 0x2710: // Connection request of a char-server
- if (RFIFOREST(fd) < 86)
- return 0;
+ else
{
- char server_name[20];
- char message[256];
- uint32 server_ip;
- uint16 server_port;
- uint16 type;
- uint16 new_;
+ ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name);
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x2711;
+ WFIFOB(fd,2) = 3;
+ WFIFOSET(fd,3);
+ }
+ }
+ return 1;
+}
- safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH);
- safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH);
- if( login_config.use_md5_passwds )
- MD5_String(sd->passwd, sd->passwd);
- sd->passwdenc = 0;
- sd->version = login_config.client_version_to_connect; // hack to skip version check
- server_ip = ntohl(RFIFOL(fd,54));
- server_port = ntohs(RFIFOW(fd,58));
- safestrncpy(server_name, (char*)RFIFOP(fd,60), 20);
- type = RFIFOW(fd,82);
- new_ = RFIFOW(fd,84);
- RFIFOSKIP(fd,86);
+//----------------------------------------------------------------------------------------
+// Default packet parsing (normal players or char-server connection requests)
+//----------------------------------------------------------------------------------------
+int parse_login(int fd)
+{
+ struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data;
- ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip);
- sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port);
- login_log(session[fd]->client_addr, sd->userid, 100, message);
+ char ip[16];
+ uint32 ipl = session[fd]->client_addr;
+ ip2str(ipl, ip);
- result = mmo_auth(sd, true);
- if( runflag == LOGINSERVER_ST_RUNNING &&
- result == -1 &&
- sd->sex == 'S' &&
- sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) &&
- !session_isValid(server[sd->account_id].fd) )
- {
- ShowStatus("Connection of the char-server '%s' accepted.\n", server_name);
- safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name));
- server[sd->account_id].fd = fd;
- server[sd->account_id].ip = server_ip;
- server[sd->account_id].port = server_port;
- server[sd->account_id].users = 0;
- server[sd->account_id].type = type;
- server[sd->account_id].new_ = new_;
+ if( session[fd]->flag.eof )
+ {
+ ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip);
+ do_close(fd);
+ return 0;
+ }
- session[fd]->func_parse = parse_fromchar;
- session[fd]->flag.server = 1;
- realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
-
- // send connection success
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x2711;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- }
- else
- {
- ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name);
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x2711;
- WFIFOB(fd,2) = 3;
- WFIFOSET(fd,3);
- }
+ if( sd == NULL )
+ {
+ // Perform ip-ban check
+ if( login_config.ipban && ipban_check(ipl) )
+ {
+ ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip);
+ login_log(ipl, "unknown", -3, "ip banned");
+ WFIFOHEAD(fd,23);
+ WFIFOW(fd,0) = 0x6a;
+ WFIFOB(fd,2) = 3; // 3 = Rejected from Server
+ WFIFOSET(fd,23);
+ set_eof(fd);
+ return 0;
}
- return 0; // processing will continue elsewhere
+ // create a session for this new connection
+ CREATE(session[fd]->session_data, struct login_session_data, 1);
+ sd = (struct login_session_data*)session[fd]->session_data;
+ sd->fd = fd;
+ }
+
+ while( RFIFOREST(fd) >= 2 )
+ {
+ uint16 command = RFIFOW(fd,0);
+
+ switch( command )
+ {
+ // New alive packet: used to verify if client is always alive.
+ case 0x0200: login_parse_keepalive(fd); break;
+ // client md5 hash (binary)
+ case 0x0204: login_parse_updclhash(fd,sd); break;
+
+ // request client login (raw password)
+ case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
+ case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
+ case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
+ // request client login (md5-hashed password)
+ case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
+ case 0x01fa: // S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
+ case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
+ case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
+ login_parse_reqauth(fd, sd, command, ip); break;
+ // Sending request of the coding key
+ case 0x01db: login_parse_reqkey(fd, sd); break;
+ // Connection request of a char-server
+ case 0x2710: login_parse_reqcharconnec(fd,sd, ip); return 0; // processing will continue elsewhere
default:
ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command);
set_eof(fd);
@@ -1604,7 +1625,9 @@
return 0;
}
-
+/*
+ * Init default configuration
+ */
void login_set_defaults()
{
login_config.login_ip = INADDR_ANY;
@@ -1620,7 +1643,8 @@
login_config.group_id_to_connect = -1;
login_config.min_group_id_to_connect = -1;
login_config.check_client_version = false;
- login_config.client_version_to_connect = 20;
+ login_config.client_version_to_connect = date2version(PACKETVER); //20120410 => 30
+ ShowInfo("loginconfig: client_version_to_connect = %d\n",login_config.client_version_to_connect);
login_config.ipban = true;
login_config.dynamic_pass_failure_ban = true;
@@ -1635,6 +1659,55 @@
login_config.client_hash_nodes = NULL;
}
+//----------------------------------
+// Reading Lan Support configuration
+//----------------------------------
+int login_lan_config_read(const char *lancfgName)
+{
+ FILE *fp;
+ int line_num = 0;
+ char line[1024], w1[64], w2[64], w3[64], w4[64];
+
+ if((fp = fopen(lancfgName, "r")) == NULL) {
+ ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
+ return 1;
+ }
+
+ while(fgets(line, sizeof(line), fp))
+ {
+ line_num++;
+ if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
+ continue;
+
+ if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4)
+ {
+ ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
+ continue;
+ }
+
+ if( strcmpi(w1, "subnet") == 0 )
+ {
+ subnet[subnet_count].mask = str2ip(w2);
+ subnet[subnet_count].char_ip = str2ip(w3);
+ subnet[subnet_count].map_ip = str2ip(w4);
+
+ if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
+ {
+ ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
+ continue;
+ }
+
+ subnet_count++;
+ }
+ }
+
+ if( subnet_count > 1 ) /* only useful if there is more than 1 available */
+ ShowStatus("Read information about %d subnetworks.\n", subnet_count);
+
+ fclose(fp);
+ return 0;
+}
+
//-----------------------------------
// Reading main configuration file
//-----------------------------------
Index: src/char/char.c
===================================================================
--- src/char/char.c (revision 17365)
+++ src/char/char.c (working copy)
@@ -33,10 +33,9 @@
#include <stdlib.h>
#include <malloc.h>
-#define MAX_STARTITEM 32
-#define CHAR_MAX_MSG 300
-static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
-
+// <editor-fold defaultstate="collapsed" desc="db_tablename">
+int db_use_sqldbs;
+char db_path[1024] = "db";
char char_db[256] = "char";
char scdata_db[256] = "sc_data";
char cart_db[256] = "cart_inventory";
@@ -67,16 +66,17 @@
char mercenary_db[256] = "mercenary";
char mercenary_owner_db[256] = "mercenary_owner";
char ragsrvinfo_db[256] = "ragsrvinfo";
+// </editor-fold>
+
// show loading/saving messages
int save_log = 1;
static DBMap* char_db_; // int char_id -> struct mmo_charstatus*
-char db_path[1024] = "db";
+#define CHAR_MAX_MSG 300
+static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
-int db_use_sqldbs;
-
struct mmo_map_server {
int fd;
uint32 ip;
@@ -115,103 +115,90 @@
int log_char = 1; // loggin char or not [devil]
int log_inter = 1; // loggin inter or not [devil]
-// Advanced subnet check [LuzZza]
-struct s_subnet {
- uint32 mask;
- uint32 char_ip;
- uint32 map_ip;
-} subnet[16];
-int subnet_count = 0;
+// check for exit signal
+// 0 is saving complete
+// other is char_id
+unsigned int save_flag = 0;
+// Initial position (it's possible to set it in conf file)
+struct point start_point = { 0, 53, 111 };
+int console = 0;
+int max_connect_user = -1;
+int gm_allow_group = -1;
+int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
+int start_zeny = 0;
+int guild_exp_rate = 100;
-struct char_session_data {
- bool auth; // whether the session is authed or not
- int account_id, login_id1, login_id2, sex;
- int found_char[MAX_CHARS]; // ids of chars on this account
- char email[40]; // e-mail (default: [email protected]) by [Yor]
- time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
- int group_id; // permission
- uint8 char_slots;
- uint32 version;
- uint8 clienttype;
- char new_name[NAME_LENGTH];
- char birthdate[10+1]; // YYYY-MM-DD
- // Pincode system
- char pincode[PINCODE_LENGTH+1];
- uint32 pincode_seed;
- time_t pincode_change;
- uint16 pincode_try;
- // Addon system
- unsigned int char_moves[MAX_CHARS]; // character moves left
-};
-
+#define MAX_STARTITEM 32
struct startitem {
int nameid; //Item ID
int amount; //Number of items
int pos; //Position (for auto-equip)
} start_items[MAX_STARTITEM+1];
-int max_connect_user = -1;
-int gm_allow_group = -1;
-int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
-int start_zeny = 0;
-int guild_exp_rate = 100;
-
// Pincode system
-#define PINCODE_OK 0
-#define PINCODE_ASK 1
-#define PINCODE_NOTSET 2
-#define PINCODE_EXPIRED 3
-#define PINCODE_NEW 4
-#define PINCODE_PASSED 7
-#define PINCODE_WRONG 8
-
+enum pincode_state {
+ PINCODE_OK = 0,
+ PINCODE_ASK,
+ PINCODE_NOTSET,
+ PINCODE_EXPIRED,
+ PINCODE_NEW,
+ PINCODE_PASSED,
+ PINCODE_WRONG,
+ PINCODE_MAXSTATE
+};
bool pincode_enabled = true;
int pincode_changetime = 0;
int pincode_maxtry = 3;
bool pincode_force = true;
-void pincode_check( int fd, struct char_session_data* sd );
-void pincode_change( int fd, struct char_session_data* sd );
-void pincode_setnew( int fd, struct char_session_data* sd );
-void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state );
-void pincode_notifyLoginPinUpdate( int account_id, char* pin );
-void pincode_notifyLoginPinError( int account_id );
-void pincode_decrypt( uint32 userSeed, char* pin );
-int pincode_compare( int fd, struct char_session_data* sd, char* pin );
-
// Addon system
bool char_move_enabled = true;
bool char_movetoused = true;
bool char_moves_unlimited = false;
-void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to );
-void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason );
-
//Custom limits for the fame lists. [Skotlex]
int fame_list_size_chemist = MAX_FAME_LIST;
int fame_list_size_smith = MAX_FAME_LIST;
int fame_list_size_taekwon = MAX_FAME_LIST;
-
// Char-server-side stored fame lists [DracoRPG]
struct fame_list smith_fame_list[MAX_FAME_LIST];
struct fame_list chemist_fame_list[MAX_FAME_LIST];
struct fame_list taekwon_fame_list[MAX_FAME_LIST];
-// check for exit signal
-// 0 is saving complete
-// other is char_id
-unsigned int save_flag = 0;
-// Initial position (it's possible to set it in conf file)
-struct point start_point = { 0, 53, 111 };
+// Advanced subnet check [LuzZza]
+struct s_subnet {
+ uint32 mask;
+ uint32 char_ip;
+ uint32 map_ip;
+} subnet[16];
+int subnet_count = 0;
-int console = 0;
+struct char_session_data {
+ bool auth; // whether the session is authed or not
+ int account_id, login_id1, login_id2, sex;
+ int found_char[MAX_CHARS]; // ids of chars on this account
+ char email[40]; // e-mail (default: [email protected]) by [Yor]
+ time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
+ int group_id; // permission
+ uint8 char_slots;
+ uint32 version;
+ uint8 clienttype;
+ char new_name[NAME_LENGTH];
+ char birthdate[10+1]; // YYYY-MM-DD
+ // Pincode system
+ char pincode[PINCODE_LENGTH+1];
+ uint32 pincode_seed;
+ time_t pincode_change;
+ uint16 pincode_try;
+ // Addon system
+ unsigned int char_moves[MAX_CHARS]; // character moves left
+};
//-----------------------------------------------------
// Auth database
//-----------------------------------------------------
#define AUTH_TIMEOUT 30000
-
struct auth_node {
int account_id;
int char_id;
@@ -223,13 +210,11 @@
int group_id;
unsigned changing_mapservers : 1;
};
-
static DBMap* auth_db; // int account_id -> struct auth_node*
//-----------------------------------------------------
// Online User Database
//-----------------------------------------------------
-
struct online_char_data {
int account_id;
int char_id;
@@ -238,8 +223,12 @@
short server; // -2: unknown server, -1: not connected, 0+: id of server
bool pincode_success;
};
+static DBMap* online_char_db; // int account_id -> struct online_char_data*
-static DBMap* online_char_db; // int account_id -> struct online_char_data*
+
+int parse_char(int fd);
+int parse_fromlogin(int fd);
+
static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
int delete_char_sql(int char_id);
@@ -1951,8 +1940,12 @@
}
//struct PACKET_CH_CHARLIST_REQ { 0x0 short PacketType}
-void char_parse_req_charlist(int fd, struct char_session_data* sd){
+int char_parse_req_charlist(int fd, struct char_session_data* sd){
+ if( RFIFOREST(fd) < 2 )
+ return 0;
+ RFIFOSKIP(fd,2);
mmo_char_send099d(fd,sd);
+ return 1;
}
//----------------------------------------
@@ -2001,13 +1994,12 @@
void mmo_char_send(int fd, struct char_session_data* sd){
ShowInfo("sd->version = %d\n",sd->version);
-#if PACKETVER >= 20130000
+ if(sd->version > 34){
mmo_char_send082d(fd,sd);
char_charlist_notify(fd,sd);
char_block_character(fd,sd);
-#endif
- //@FIXME dump from kro doesn't show 6b transmission
- mmo_char_send006b(fd,sd);
+ }
+ mmo_char_send006b(fd,sd); //@FIXME dump from kro doesn't show 6b transmission
}
int char_married(int pl1, int pl2)
@@ -2184,369 +2176,6 @@
ShowStatus("Awaiting maps from map-server.\n");
}
-
-int parse_fromlogin(int fd) {
- struct char_session_data* sd = NULL;
- int i;
-
- // only process data from the login-server
- if( fd != login_fd ) {
- ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
- do_close(fd);
- return 0;
- }
-
- if( session[fd]->flag.eof ) {
- do_close(fd);
- login_fd = -1;
- loginif_on_disconnect();
- return 0;
- } else if ( session[fd]->flag.ping ) {/* we've reached stall time */
- if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
- set_eof(fd);
- return 0;
- } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
- WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
- WFIFOW(fd,0) = 0x2719;
- WFIFOSET(fd,2);
-
- session[fd]->flag.ping = 2;
- }
- }
-
- sd = (struct char_session_data*)session[fd]->session_data;
-
- while(RFIFOREST(fd) >= 2) {
- uint16 command = RFIFOW(fd,0);
-
- switch( command )
- {
-
- // acknowledgement of connect-to-loginserver request
- case 0x2711:
- if (RFIFOREST(fd) < 3)
- return 0;
-
- if (RFIFOB(fd,2)) {
- //printf("connect login server error : %d\n", RFIFOB(fd,2));
- ShowError("Can not connect to login-server.\n");
- ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
- ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
- ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
- set_eof(fd);
- return 0;
- } else {
- ShowStatus("Connected to login-server (connection #%d).\n", fd);
- loginif_on_ready();
- }
- RFIFOSKIP(fd,3);
- break;
-
- // acknowledgement of account authentication request
- case 0x2713:
- if (RFIFOREST(fd) < 25)
- return 0;
- {
- int account_id = RFIFOL(fd,2);
- uint32 login_id1 = RFIFOL(fd,6);
- uint32 login_id2 = RFIFOL(fd,10);
- uint8 sex = RFIFOB(fd,14);
- uint8 result = RFIFOB(fd,15);
- int request_id = RFIFOL(fd,16);
- uint32 version = RFIFOL(fd,20);
- uint8 clienttype = RFIFOB(fd,24);
- RFIFOSKIP(fd,25);
-
- if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
- !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
- {
- int client_fd = request_id;
- sd->version = version;
- sd->clienttype = clienttype;
- switch( result )
- {
- case 0:// ok
- char_auth_ok(client_fd, sd);
- break;
- case 1:// auth failed
- WFIFOHEAD(client_fd,3);
- WFIFOW(client_fd,0) = 0x6c;
- WFIFOB(client_fd,2) = 0;// rejected from server
- WFIFOSET(client_fd,3);
- break;
- }
- }
- }
- break;
-
- case 0x2717: // account data
- if (RFIFOREST(fd) < 72)
- return 0;
-
- // find the authenticated session with this account id
- 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) );
- if( i < fd_max )
- {
- int server_id;
- memcpy(sd->email, RFIFOP(fd,6), 40);
- sd->expiration_time = (time_t)RFIFOL(fd,46);
- sd->group_id = RFIFOB(fd,50);
- sd->char_slots = RFIFOB(fd,51);
- if( sd->char_slots > MAX_CHARS ) {
- 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);
- sd->char_slots = MAX_CHARS;/* cap to maximum */
- } else if ( !sd->char_slots )/* no value aka 0 in sql */
- sd->char_slots = MAX_CHARS;/* cap to maximum */
- safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
- safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
- sd->pincode_change = (time_t)RFIFOL(fd,68);
- ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
- // continued from char_auth_ok...
- if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
- (max_connect_user == 0 && sd->group_id != gm_allow_group) ||
- ( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
- // refuse connection (over populated)
- WFIFOHEAD(i,3);
- WFIFOW(i,0) = 0x6c;
- WFIFOW(i,2) = 0;
- WFIFOSET(i,3);
- } else {
- // send characters to player
- mmo_char_send(i, sd);
-#if PACKETVER >= 20110309
- if( pincode_enabled ){
- // PIN code system enabled
- if( strlen( sd->pincode ) <= 0 ){
- // No PIN code has been set yet
- if( pincode_force ){
- pincode_sendstate( i, sd, PINCODE_NEW );
- }else{
- pincode_sendstate( i, sd, PINCODE_PASSED );
- }
- }else{
- if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
- struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
-
- if( node != NULL && node->pincode_success ){
- // User has already passed the check
- pincode_sendstate( i, sd, PINCODE_PASSED );
- }else{
- // Ask user for his PIN code
- pincode_sendstate( i, sd, PINCODE_ASK );
- }
- }else{
- // User hasnt changed his PIN code too long
- pincode_sendstate( i, sd, PINCODE_EXPIRED );
- }
- }
- }else{
- // PIN code system disabled
- pincode_sendstate( i, sd, PINCODE_OK );
- }
-#endif
- }
- }
- RFIFOSKIP(fd,72);
- break;
-
- // login-server alive packet
- case 0x2718:
- if (RFIFOREST(fd) < 2)
- return 0;
- RFIFOSKIP(fd,2);
- session[fd]->flag.ping = 0;
- break;
-
- // changesex reply
- case 0x2723:
- if (RFIFOREST(fd) < 7)
- return 0;
- {
- unsigned char buf[7];
-
- int acc = RFIFOL(fd,2);
- int sex = RFIFOB(fd,6);
- RFIFOSKIP(fd,7);
-
- if( acc > 0 )
- {// TODO: Is this even possible?
- int char_id[MAX_CHARS];
- int class_[MAX_CHARS];
- int guild_id[MAX_CHARS];
- int num;
- char* data;
-
- struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
- if( node != NULL )
- node->sex = sex;
-
- // get characters
- if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
- Sql_ShowDebug(sql_handle);
- for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
- {
- Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
- Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
- Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
- }
- num = i;
- for( i = 0; i < num; ++i )
- {
- if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
- class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
- class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
- class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
- class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
- class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
- class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
- {
- // job modification
- if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
- class_[i] = (sex ? JOB_BARD : JOB_DANCER);
- else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
- class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
- else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
- class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
- else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
- class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
- else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
- class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
- else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
- class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
- else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
- class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
- }
-
- 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]) )
- Sql_ShowDebug(sql_handle);
-
- if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
- inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
- }
- Sql_FreeResult(sql_handle);
-
- // disconnect player if online on char-server
- disconnect_player(acc);
- }
-
- // notify all mapservers about this change
- WBUFW(buf,0) = 0x2b0d;
- WBUFL(buf,2) = acc;
- WBUFB(buf,6) = sex;
- mapif_sendall(buf, 7);
- }
- break;
-
- // reply to an account_reg2 registry request
- case 0x2729:
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
-
- { //Receive account_reg2 registry, forward to map servers.
- unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
- memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
- WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
- mapif_sendall(buf, WBUFW(buf,2));
- RFIFOSKIP(fd, RFIFOW(fd,2));
- }
- break;
-
- // State change of account/ban notification (from login-server)
- case 0x2731:
- if (RFIFOREST(fd) < 11)
- return 0;
-
- { // send to all map-servers to disconnect the player
- unsigned char buf[11];
- WBUFW(buf,0) = 0x2b14;
- WBUFL(buf,2) = RFIFOL(fd,2);
- WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
- WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
- mapif_sendall(buf, 11);
- }
- // disconnect player if online on char-server
- disconnect_player(RFIFOL(fd,2));
-
- RFIFOSKIP(fd,11);
- break;
-
- // Login server request to kick a character out. [Skotlex]
- case 0x2734:
- if (RFIFOREST(fd) < 6)
- return 0;
- {
- int aid = RFIFOL(fd,2);
- struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
- RFIFOSKIP(fd,6);
- if( character != NULL )
- {// account is already marked as online!
- if( character->server > -1 )
- { //Kick it from the map server it is on.
- mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
- if (character->waiting_disconnect == INVALID_TIMER)
- character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
- }
- else
- {// Manual kick from char server.
- struct char_session_data *tsd;
- int i;
- ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
- if( i < fd_max )
- {
- WFIFOHEAD(i,3);
- WFIFOW(i,0) = 0x81;
- WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
- WFIFOSET(i,3);
- set_eof(i);
- }
- else // still moving to the map-server
- set_char_offline(-1, aid);
- }
- }
- idb_remove(auth_db, aid);// reject auth attempts from map-server
- }
- break;
-
- // ip address update signal from login server
- case 0x2735:
- {
- unsigned char buf[2];
- uint32 new_ip = 0;
-
- WBUFW(buf,0) = 0x2b1e;
- mapif_sendall(buf, 2);
-
- new_ip = host2ip(login_ip_str);
- if (new_ip && new_ip != login_ip)
- login_ip = new_ip; //Update login ip, too.
-
- new_ip = host2ip(char_ip_str);
- if (new_ip && new_ip != char_ip)
- { //Update ip.
- char_ip = new_ip;
- ShowInfo("Updating IP for [%s].\n", char_ip_str);
- // notify login server about the change
- WFIFOHEAD(fd,6);
- WFIFOW(fd,0) = 0x2736;
- WFIFOL(fd,2) = htonl(char_ip);
- WFIFOSET(fd,6);
- }
-
- RFIFOSKIP(fd,2);
- }
- break;
-
- default:
- ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
- set_eof(fd);
- return 0;
- }
- }
-
- RFIFOFLUSH(fd);
- return 0;
-}
-
int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data);
int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
@@ -2779,729 +2408,851 @@
mapif_server_reset(id);
}
+void do_init_mapif(void)
+{
+ int i;
+ for( i = 0; i < ARRAYLENGTH(server); ++i )
+ mapif_server_init(i);
+}
-int parse_frommap(int fd)
+void do_final_mapif(void)
{
+ int i;
+ for( i = 0; i < ARRAYLENGTH(server); ++i )
+ mapif_server_destroy(i);
+}
+
+// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
+// If found, returns the server's index in the 'server' array (otherwise returns -1).
+int search_mapserver(unsigned short map, uint32 ip, uint16 port)
+{
int i, j;
- int id;
- ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
- if( id == ARRAYLENGTH(server) )
- {// not a map server
- ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
- do_close(fd);
- return 0;
+ for(i = 0; i < ARRAYLENGTH(server); i++)
+ {
+ if (server[i].fd > 0
+ && (ip == (uint32)-1 || server[i].ip == ip)
+ && (port == (uint16)-1 || server[i].port == port))
+ {
+ for (j = 0; server[i].map[j]; j++)
+ if (server[i].map[j] == map)
+ return i;
+ }
}
- if( session[fd]->flag.eof )
- {
- do_close(fd);
- server[id].fd = -1;
- mapif_on_disconnect(id);
+
+ return -1;
+}
+
+// Initialization process (currently only initialization inter_mapif)
+static int char_mapif_init(int fd)
+{
+ return inter_mapif_init(fd);
+}
+
+//--------------------------------------------
+// Test to know if an IP come from LAN or WAN.
+//--------------------------------------------
+int lan_subnetcheck(uint32 ip)
+{
+ int i;
+ ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
+ if( i < subnet_count ) {
+ 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));
+ return subnet[i].map_ip;
+ } else {
+ ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
return 0;
}
+}
- while(RFIFOREST(fd) >= 2){
- switch(RFIFOW(fd,0)){
- case 0x2afa: // Receiving map names list from the map-server
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
+//For use in packets that depend on an sd being present [Skotlex]
+#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
- memset(server[id].map, 0, sizeof(server[id].map));
- j = 0;
- for(i = 4; i < RFIFOW(fd,2); i += 4) {
- server[id].map[j] = RFIFOW(fd,i);
- j++;
- }
+///
+/// Map IF
+///
- ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
- id, j, CONVIP(server[id].ip), server[id].port);
- ShowStatus("Map-server %d loading complete.\n", id);
+int char_parsemap_getmapname(int fd, int id){
+ int j = 0, i = 0;
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
- // send name for wisp to player
- WFIFOHEAD(fd, 3 + NAME_LENGTH);
- WFIFOW(fd,0) = 0x2afb;
- WFIFOB(fd,2) = 0;
- memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
- WFIFOSET(fd,3+NAME_LENGTH);
+ memset(server[id].map, 0, sizeof(server[id].map));
+ for(i = 4; i < RFIFOW(fd,2); i += 4) {
+ server[id].map[j] = RFIFOW(fd,i);
+ j++;
+ }
- char_send_fame_list(fd); //Send fame list.
+ ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
+ id, j, CONVIP(server[id].ip), server[id].port);
+ ShowStatus("Map-server %d loading complete.\n", id);
- {
- unsigned char buf[16384];
- int x;
- if (j == 0) {
- ShowWarning("Map-server %d has NO maps.\n", id);
- } else {
- // Transmitting maps information to the other map-servers
- WBUFW(buf,0) = 0x2b04;
- WBUFW(buf,2) = j * 4 + 10;
- WBUFL(buf,4) = htonl(server[id].ip);
- WBUFW(buf,8) = htons(server[id].port);
- memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
- mapif_sendallwos(fd, buf, WBUFW(buf,2));
- }
- // Transmitting the maps of the other map-servers to the new map-server
- for(x = 0; x < ARRAYLENGTH(server); x++) {
- if (server[x].fd > 0 && x != id) {
- WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
- WFIFOW(fd,0) = 0x2b04;
- WFIFOL(fd,4) = htonl(server[x].ip);
- WFIFOW(fd,8) = htons(server[x].port);
- j = 0;
- for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
- if (server[x].map[i])
- WFIFOW(fd,10+(j++)*4) = server[x].map[i];
- if (j > 0) {
- WFIFOW(fd,2) = j * 4 + 10;
- WFIFOSET(fd,WFIFOW(fd,2));
- }
+ // send name for wisp to player
+ WFIFOHEAD(fd, 3 + NAME_LENGTH);
+ WFIFOW(fd,0) = 0x2afb;
+ WFIFOB(fd,2) = 0;
+ memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
+ WFIFOSET(fd,3+NAME_LENGTH);
+
+ char_send_fame_list(fd); //Send fame list.
+
+ {
+ unsigned char buf[16384];
+ int x;
+ if (j == 0) {
+ ShowWarning("Map-server %d has NO maps.\n", id);
+ } else {
+ // Transmitting maps information to the other map-servers
+ WBUFW(buf,0) = 0x2b04;
+ WBUFW(buf,2) = j * 4 + 10;
+ WBUFL(buf,4) = htonl(server[id].ip);
+ WBUFW(buf,8) = htons(server[id].port);
+ memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
+ mapif_sendallwos(fd, buf, WBUFW(buf,2));
+ }
+ // Transmitting the maps of the other map-servers to the new map-server
+ for(x = 0; x < ARRAYLENGTH(server); x++) {
+ if (server[x].fd > 0 && x != id) {
+ WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map));
+ WFIFOW(fd,0) = 0x2b04;
+ WFIFOL(fd,4) = htonl(server[x].ip);
+ WFIFOW(fd,8) = htons(server[x].port);
+ j = 0;
+ for(i = 0; i < ARRAYLENGTH(server[x].map); i++)
+ if (server[x].map[i])
+ WFIFOW(fd,10+(j++)*4) = server[x].map[i];
+ if (j > 0) {
+ WFIFOW(fd,2) = j * 4 + 10;
+ WFIFOSET(fd,WFIFOW(fd,2));
}
}
- }
- RFIFOSKIP(fd,RFIFOW(fd,2));
- break;
+ }
+ }
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ return 1;
+}
- case 0x2afc: //Packet command is now used for sc_data request. [Skotlex]
- if (RFIFOREST(fd) < 10)
- return 0;
+int char_parsemap_askscdata(int fd, int id){
+ if (RFIFOREST(fd) < 10)
+ return 0;
+ {
+#ifdef ENABLE_SC_SAVING
+ int aid, cid;
+ aid = RFIFOL(fd,2);
+ cid = RFIFOL(fd,6);
+ if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
+ scdata_db, aid, cid) )
{
-#ifdef ENABLE_SC_SAVING
- int aid, cid;
- aid = RFIFOL(fd,2);
- cid = RFIFOL(fd,6);
- if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
- scdata_db, aid, cid) )
+ Sql_ShowDebug(sql_handle);
+ return 0;
+ }
+ if( Sql_NumRows(sql_handle) > 0 )
+ {
+ struct status_change_data scdata;
+ int count;
+ char* data;
+
+ WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
+ WFIFOW(fd,0) = 0x2b1d;
+ WFIFOL(fd,4) = aid;
+ WFIFOL(fd,8) = cid;
+ for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
{
- Sql_ShowDebug(sql_handle);
- break;
+ Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
+ Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
+ Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
+ Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
+ Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
+ Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
+ memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
}
- if( Sql_NumRows(sql_handle) > 0 )
+ if (count >= 50)
+ ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
+ if (count > 0)
{
- struct status_change_data scdata;
- int count;
- char* data;
+ WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
+ WFIFOW(fd,12) = count;
+ WFIFOSET(fd,WFIFOW(fd,2));
- WFIFOHEAD(fd,14+50*sizeof(struct status_change_data));
- WFIFOW(fd,0) = 0x2b1d;
- WFIFOL(fd,4) = aid;
- WFIFOL(fd,8) = cid;
- for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
- {
- Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
- Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data);
- Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data);
- Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
- Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
- Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
- memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
- }
- if (count >= 50)
- ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
- if (count > 0)
- {
- WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
- WFIFOW(fd,12) = count;
- WFIFOSET(fd,WFIFOW(fd,2));
-
- //Clear the data once loaded.
- if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
- Sql_ShowDebug(sql_handle);
- }
+ //Clear the data once loaded.
+ if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
+ Sql_ShowDebug(sql_handle);
}
- Sql_FreeResult(sql_handle);
+ }
+ Sql_FreeResult(sql_handle);
#endif
- RFIFOSKIP(fd, 10);
- }
- break;
+ RFIFOSKIP(fd, 10);
+ }
+ return 1;
+}
- case 0x2afe: //set MAP user count
- if (RFIFOREST(fd) < 4)
- return 0;
- if (RFIFOW(fd,2) != server[id].users) {
- server[id].users = RFIFOW(fd,2);
- ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
- }
- RFIFOSKIP(fd, 4);
- break;
+int char_parsemap_getusercount(int fd, int id){
+ if (RFIFOREST(fd) < 4)
+ return 0;
+ if (RFIFOW(fd,2) != server[id].users) {
+ server[id].users = RFIFOW(fd,2);
+ ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
+ }
+ RFIFOSKIP(fd, 4);
+ return 1;
+}
- case 0x2aff: //set MAP users
- if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- {
- //TODO: When data mismatches memory, update guild/party online/offline states.
- int aid, cid;
- struct online_char_data* character;
+int char_parsemap_regmapuser(int fd, int id){
+ int i;
+ if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ {
+ //TODO: When data mismatches memory, update guild/party online/offline states.
+ int aid, cid;
+ struct online_char_data* character;
- server[id].users = RFIFOW(fd,4);
- online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
- for(i = 0; i < server[id].users; i++) {
- aid = RFIFOL(fd,6+i*8);
- cid = RFIFOL(fd,6+i*8+4);
- character = idb_ensure(online_char_db, aid, create_online_char_data);
- if( character->server > -1 && character->server != id )
- {
- ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
- character->account_id, character->char_id, character->server, id, aid, cid);
- mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
- }
- character->server = id;
- character->char_id = cid;
+ server[id].users = RFIFOW(fd,4);
+ online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
+ for(i = 0; i < server[id].users; i++) {
+ aid = RFIFOL(fd,6+i*8);
+ cid = RFIFOL(fd,6+i*8+4);
+ character = idb_ensure(online_char_db, aid, create_online_char_data);
+ if( character->server > -1 && character->server != id )
+ {
+ ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
+ character->account_id, character->char_id, character->server, id, aid, cid);
+ mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
}
- //If any chars remain in -2, they will be cleaned in the cleanup timer.
- RFIFOSKIP(fd,RFIFOW(fd,2));
+ character->server = id;
+ character->char_id = cid;
}
- break;
+ //If any chars remain in -2, they will be cleaned in the cleanup timer.
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ }
+ return 1;
+}
- case 0x2b01: // Receive character data from map-server for saving
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
+int char_parsemap_reqsavechar(int fd, int id){
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ {
+ int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
+ struct online_char_data* character;
+
+ if (size - 13 != sizeof(struct mmo_charstatus))
{
- int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
- struct online_char_data* character;
-
- if (size - 13 != sizeof(struct mmo_charstatus))
- {
- ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
- RFIFOSKIP(fd,size);
- break;
- }
- //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
- if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
- (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
- character->char_id == cid))
- {
- struct mmo_charstatus char_dat;
- memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
- mmo_char_tosql(cid, &char_dat);
- } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off.
- ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
- set_char_online(id, cid, aid);
- }
-
- if (RFIFOB(fd,12))
- { //Flag, set character offline after saving. [Skotlex]
- set_char_offline(cid, aid);
- WFIFOHEAD(fd,10);
- WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
- WFIFOL(fd,2) = aid;
- WFIFOL(fd,6) = cid;
- WFIFOSET(fd,10);
- }
+ ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
RFIFOSKIP(fd,size);
+ return 0;
}
- break;
+ //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
+ if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
+ (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
+ character->char_id == cid))
+ {
+ struct mmo_charstatus char_dat;
+ memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
+ mmo_char_tosql(cid, &char_dat);
+ } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off.
+ ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
+ set_char_online(id, cid, aid);
+ }
- case 0x2b02: // req char selection
- if( RFIFOREST(fd) < 18 )
- return 0;
- else{
- int account_id = RFIFOL(fd,2);
- uint32 login_id1 = RFIFOL(fd,6);
- uint32 login_id2 = RFIFOL(fd,10);
- uint32 ip = RFIFOL(fd,14);
- RFIFOSKIP(fd,18);
+ if (RFIFOB(fd,12))
+ { //Flag, set character offline after saving. [Skotlex]
+ set_char_offline(cid, aid);
+ WFIFOHEAD(fd,10);
+ WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
+ WFIFOL(fd,2) = aid;
+ WFIFOL(fd,6) = cid;
+ WFIFOSET(fd,10);
+ }
+ RFIFOSKIP(fd,size);
+ }
+ return 1;
+}
- if( runflag != CHARSERVER_ST_RUNNING ){
- WFIFOHEAD(fd,7);
- WFIFOW(fd,0) = 0x2b03;
- WFIFOL(fd,2) = account_id;
- WFIFOB(fd,6) = 0;// not ok
- WFIFOSET(fd,7);
- }else{
- struct auth_node* node;
+int char_parsemap_authok(int fd, int id){
+ if( RFIFOREST(fd) < 18 )
+ return 0;
+ else{
+ int account_id = RFIFOL(fd,2);
+ uint32 login_id1 = RFIFOL(fd,6);
+ uint32 login_id2 = RFIFOL(fd,10);
+ uint32 ip = RFIFOL(fd,14);
+ RFIFOSKIP(fd,18);
- // create temporary auth entry
- CREATE(node, struct auth_node, 1);
- node->account_id = account_id;
- node->char_id = 0;
- node->login_id1 = login_id1;
- node->login_id2 = login_id2;
- //node->sex = 0;
- node->ip = ntohl(ip);
- //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
- //node->gmlevel = 0;
- idb_put(auth_db, account_id, node);
+ if( runflag != CHARSERVER_ST_RUNNING ){
+ WFIFOHEAD(fd,7);
+ WFIFOW(fd,0) = 0x2b03;
+ WFIFOL(fd,2) = account_id;
+ WFIFOB(fd,6) = 0;// not ok
+ WFIFOSET(fd,7);
+ }else{
+ struct auth_node* node;
- //Set char to "@ char select" in online db [Kevin]
- set_char_charselect(account_id);
+ // create temporary auth entry
+ CREATE(node, struct auth_node, 1);
+ node->account_id = account_id;
+ node->char_id = 0;
+ node->login_id1 = login_id1;
+ node->login_id2 = login_id2;
+ //node->sex = 0;
+ node->ip = ntohl(ip);
+ //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
+ //node->gmlevel = 0;
+ idb_put(auth_db, account_id, node);
- {
- struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
+ //Set char to "@ char select" in online db [Kevin]
+ set_char_charselect(account_id);
- if( character != NULL ){
- character->pincode_success = true;
- }
- }
+ {
+ struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id);
- WFIFOHEAD(fd,7);
- WFIFOW(fd,0) = 0x2b03;
- WFIFOL(fd,2) = account_id;
- WFIFOB(fd,6) = 1;// ok
- WFIFOSET(fd,7);
+ if( character != NULL ){
+ character->pincode_success = true;
}
}
- break;
- case 0x2b05: // request "change map server"
- if (RFIFOREST(fd) < 39)
- return 0;
- {
- int map_id, map_fd = -1;
- struct mmo_charstatus* char_data;
- struct mmo_charstatus char_dat;
+ WFIFOHEAD(fd,7);
+ WFIFOW(fd,0) = 0x2b03;
+ WFIFOL(fd,2) = account_id;
+ WFIFOB(fd,6) = 1;// ok
+ WFIFOSET(fd,7);
+ }
+ }
+ return 1;
+}
- map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
- if (map_id >= 0)
- map_fd = server[map_id].fd;
- //Char should just had been saved before this packet, so this should be safe. [Skotlex]
+int char_parsemap_reqchangemapserv(int fd, int id){
+ if (RFIFOREST(fd) < 39)
+ return 0;
+ {
+ int map_id, map_fd = -1;
+ struct mmo_charstatus* char_data;
+ struct mmo_charstatus char_dat;
+
+ map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
+ if (map_id >= 0)
+ map_fd = server[map_id].fd;
+ //Char should just had been saved before this packet, so this should be safe. [Skotlex]
+ char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
+ if (char_data == NULL) { //Really shouldn't happen.
+ mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
- if (char_data == NULL) { //Really shouldn't happen.
- mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
- char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
- }
+ }
- if( runflag == CHARSERVER_ST_RUNNING &&
- session_isActive(map_fd) &&
- char_data )
- { //Send the map server the auth of this player.
- struct online_char_data* data;
- struct auth_node* node;
+ if( runflag == CHARSERVER_ST_RUNNING &&
+ session_isActive(map_fd) &&
+ char_data )
+ { //Send the map server the auth of this player.
+ struct online_char_data* data;
+ struct auth_node* node;
- //Update the "last map" as this is where the player must be spawned on the new map server.
- char_data->last_point.map = RFIFOW(fd,18);
- char_data->last_point.x = RFIFOW(fd,20);
- char_data->last_point.y = RFIFOW(fd,22);
- char_data->sex = RFIFOB(fd,30);
+ //Update the "last map" as this is where the player must be spawned on the new map server.
+ char_data->last_point.map = RFIFOW(fd,18);
+ char_data->last_point.x = RFIFOW(fd,20);
+ char_data->last_point.y = RFIFOW(fd,22);
+ char_data->sex = RFIFOB(fd,30);
- // create temporary auth entry
- CREATE(node, struct auth_node, 1);
- node->account_id = RFIFOL(fd,2);
- node->char_id = RFIFOL(fd,14);
- node->login_id1 = RFIFOL(fd,6);
- node->login_id2 = RFIFOL(fd,10);
- node->sex = RFIFOB(fd,30);
- node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
- node->ip = ntohl(RFIFOL(fd,31));
- node->group_id = RFIFOL(fd,35);
- node->changing_mapservers = 1;
- idb_put(auth_db, RFIFOL(fd,2), node);
+ // create temporary auth entry
+ CREATE(node, struct auth_node, 1);
+ node->account_id = RFIFOL(fd,2);
+ node->char_id = RFIFOL(fd,14);
+ node->login_id1 = RFIFOL(fd,6);
+ node->login_id2 = RFIFOL(fd,10);
+ node->sex = RFIFOB(fd,30);
+ node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing)
+ node->ip = ntohl(RFIFOL(fd,31));
+ node->group_id = RFIFOL(fd,35);
+ node->changing_mapservers = 1;
+ idb_put(auth_db, RFIFOL(fd,2), node);
- data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
- data->char_id = char_data->char_id;
- data->server = map_id; //Update server where char is.
+ data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
+ data->char_id = char_data->char_id;
+ data->server = map_id; //Update server where char is.
- //Reply with an ack.
- WFIFOHEAD(fd,30);
- WFIFOW(fd,0) = 0x2b06;
- memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
- WFIFOSET(fd,30);
- } else { //Reply with nak
- WFIFOHEAD(fd,30);
- WFIFOW(fd,0) = 0x2b06;
- memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
- WFIFOL(fd,6) = 0; //Set login1 to 0.
- WFIFOSET(fd,30);
- }
- RFIFOSKIP(fd,39);
+ //Reply with an ack.
+ WFIFOHEAD(fd,30);
+ WFIFOW(fd,0) = 0x2b06;
+ memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
+ WFIFOSET(fd,30);
+ } else { //Reply with nak
+ WFIFOHEAD(fd,30);
+ WFIFOW(fd,0) = 0x2b06;
+ memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
+ WFIFOL(fd,6) = 0; //Set login1 to 0.
+ WFIFOSET(fd,30);
}
- break;
+ RFIFOSKIP(fd,39);
+ }
+ return 1;
+}
- case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
- if (RFIFOREST(fd) < 10)
- return 0;
- {
- int char_id, friend_id;
- char_id = RFIFOL(fd,2);
- friend_id = RFIFOL(fd,6);
- if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
- friend_db, char_id, friend_id) ) {
- Sql_ShowDebug(sql_handle);
- break;
- }
- RFIFOSKIP(fd,10);
- }
- break;
+int char_parsemap_askrmfriend(int fd, int id){
+ if (RFIFOREST(fd) < 10)
+ return 0;
+ {
+ int char_id, friend_id;
+ char_id = RFIFOL(fd,2);
+ friend_id = RFIFOL(fd,6);
+ if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1",
+ friend_db, char_id, friend_id) ) {
+ Sql_ShowDebug(sql_handle);
+ return 0;
+ }
+ RFIFOSKIP(fd,10);
+ }
+ return 1;
+}
- case 0x2b08: // char name request
- if (RFIFOREST(fd) < 6)
- return 0;
+int char_parsemap_reqcharname(int fd, int id){
+ if (RFIFOREST(fd) < 6)
+ return 0;
- WFIFOHEAD(fd,30);
- WFIFOW(fd,0) = 0x2b09;
- WFIFOL(fd,2) = RFIFOL(fd,2);
- char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
- WFIFOSET(fd,30);
+ WFIFOHEAD(fd,30);
+ WFIFOW(fd,0) = 0x2b09;
+ WFIFOL(fd,2) = RFIFOL(fd,2);
+ char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6));
+ WFIFOSET(fd,30);
- RFIFOSKIP(fd,6);
- break;
+ RFIFOSKIP(fd,6);
+ return 1;
+}
- case 0x2b0c: // Map server send information to change an email of an account -> login-server
- if (RFIFOREST(fd) < 86)
- return 0;
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd,86);
- memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
- WFIFOW(login_fd,0) = 0x2722;
- WFIFOSET(login_fd,86);
- }
- RFIFOSKIP(fd, 86);
- break;
+int char_parsemap_reqnewemail(int fd, int id){
+ if (RFIFOREST(fd) < 86)
+ return 0;
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd,86);
+ memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
+ WFIFOW(login_fd,0) = 0x2722;
+ WFIFOSET(login_fd,86);
+ }
+ RFIFOSKIP(fd, 86);
+ return 1;
+}
- case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server)
- if (RFIFOREST(fd) < 44)
- return 0;
- {
- int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
- char esc_name[NAME_LENGTH*2+1];
+int char_parsemap_fwlog_changestatus(int fd, int id){
+ if (RFIFOREST(fd) < 44)
+ return 0;
+ {
+ int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
+ char esc_name[NAME_LENGTH*2+1];
- int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
- const char* name = (char*)RFIFOP(fd,6); // name of the target character
- int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
- short year = RFIFOW(fd,32);
- short month = RFIFOW(fd,34);
- short day = RFIFOW(fd,36);
- short hour = RFIFOW(fd,38);
- short minute = RFIFOW(fd,40);
- short second = RFIFOW(fd,42);
- RFIFOSKIP(fd,44);
+ int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
+ const char* name = (char*)RFIFOP(fd,6); // name of the target character
+ int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
+ short year = RFIFOW(fd,32);
+ short month = RFIFOW(fd,34);
+ short day = RFIFOW(fd,36);
+ short hour = RFIFOW(fd,38);
+ short minute = RFIFOW(fd,40);
+ short second = RFIFOW(fd,42);
+ RFIFOSKIP(fd,44);
- Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
- if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
- Sql_ShowDebug(sql_handle);
- else
- if( Sql_NumRows(sql_handle) == 0 )
- {
- result = 1; // 1-player not found
- }
- else
- if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
- Sql_ShowDebug(sql_handle);
- //FIXME: set proper result value?
- else
- {
- char name[NAME_LENGTH];
- int account_id;
- char* data;
+ Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
+ if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
+ Sql_ShowDebug(sql_handle);
+ else
+ if( Sql_NumRows(sql_handle) == 0 )
+ {
+ result = 1; // 1-player not found
+ }
+ else
+ if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
+ Sql_ShowDebug(sql_handle);
+ //FIXME: set proper result value?
+ else
+ {
+ char name[NAME_LENGTH];
+ int account_id;
+ char* data;
- Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
- Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
+ Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
+ Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
- if( login_fd <= 0 )
- result = 3; // 3-login-server offline
- //FIXME: need to move this check to login server [ultramage]
+ if( login_fd <= 0 )
+ result = 3; // 3-login-server offline
+ //FIXME: need to move this check to login server [ultramage]
// else
// if( acc != -1 && isGM(acc) < isGM(account_id) )
// result = 2; // 2-gm level too low
- else
- switch( type ) {
- case 1: // block
- WFIFOHEAD(login_fd,10);
- WFIFOW(login_fd,0) = 0x2724;
- WFIFOL(login_fd,2) = account_id;
- WFIFOL(login_fd,6) = 5; // new account status
- WFIFOSET(login_fd,10);
- break;
- case 2: // ban
- WFIFOHEAD(login_fd,18);
- WFIFOW(login_fd, 0) = 0x2725;
- WFIFOL(login_fd, 2) = account_id;
- WFIFOW(login_fd, 6) = year;
- WFIFOW(login_fd, 8) = month;
- WFIFOW(login_fd,10) = day;
- WFIFOW(login_fd,12) = hour;
- WFIFOW(login_fd,14) = minute;
- WFIFOW(login_fd,16) = second;
- WFIFOSET(login_fd,18);
- break;
- case 3: // unblock
- WFIFOHEAD(login_fd,10);
- WFIFOW(login_fd,0) = 0x2724;
- WFIFOL(login_fd,2) = account_id;
- WFIFOL(login_fd,6) = 0; // new account status
- WFIFOSET(login_fd,10);
- break;
- case 4: // unban
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x272a;
- WFIFOL(login_fd,2) = account_id;
- WFIFOSET(login_fd,6);
- break;
- case 5: // changesex
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x2727;
- WFIFOL(login_fd,2) = account_id;
- WFIFOSET(login_fd,6);
- break;
- }
+ else
+ switch( type ) {
+ case 1: // block
+ WFIFOHEAD(login_fd,10);
+ WFIFOW(login_fd,0) = 0x2724;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOL(login_fd,6) = 5; // new account status
+ WFIFOSET(login_fd,10);
+ break;
+ case 2: // ban
+ WFIFOHEAD(login_fd,18);
+ WFIFOW(login_fd, 0) = 0x2725;
+ WFIFOL(login_fd, 2) = account_id;
+ WFIFOW(login_fd, 6) = year;
+ WFIFOW(login_fd, 8) = month;
+ WFIFOW(login_fd,10) = day;
+ WFIFOW(login_fd,12) = hour;
+ WFIFOW(login_fd,14) = minute;
+ WFIFOW(login_fd,16) = second;
+ WFIFOSET(login_fd,18);
+ break;
+ case 3: // unblock
+ WFIFOHEAD(login_fd,10);
+ WFIFOW(login_fd,0) = 0x2724;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOL(login_fd,6) = 0; // new account status
+ WFIFOSET(login_fd,10);
+ break;
+ case 4: // unban
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x272a;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOSET(login_fd,6);
+ break;
+ case 5: // changesex
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x2727;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOSET(login_fd,6);
+ break;
}
+ }
- Sql_FreeResult(sql_handle);
+ Sql_FreeResult(sql_handle);
- // send answer if a player ask, not if the server ask
- if( acc != -1 && type != 5) { // Don't send answer for changesex
- WFIFOHEAD(fd,34);
- WFIFOW(fd, 0) = 0x2b0f;
- WFIFOL(fd, 2) = acc;
- safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
- WFIFOW(fd,30) = type;
- WFIFOW(fd,32) = result;
- WFIFOSET(fd,34);
- }
+ // send answer if a player ask, not if the server ask
+ if( acc != -1 && type != 5) { // Don't send answer for changesex
+ WFIFOHEAD(fd,34);
+ WFIFOW(fd, 0) = 0x2b0f;
+ WFIFOL(fd, 2) = acc;
+ safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
+ WFIFOW(fd,30) = type;
+ WFIFOW(fd,32) = result;
+ WFIFOSET(fd,34);
}
- break;
+ }
+ return 1;
+}
- case 0x2b10: // Update and send fame ranking list
- if (RFIFOREST(fd) < 11)
- return 0;
+int char_parsemap_updfamelist(int fd, int id){
+ if (RFIFOREST(fd) < 11)
+ return 0;
+ {
+ int cid = RFIFOL(fd, 2);
+ int fame = RFIFOL(fd, 6);
+ char type = RFIFOB(fd, 10);
+ int size;
+ struct fame_list* list;
+ int player_pos;
+ int fame_pos;
+
+ switch(type)
{
- int cid = RFIFOL(fd, 2);
- int fame = RFIFOL(fd, 6);
- char type = RFIFOB(fd, 10);
- int size;
- struct fame_list* list;
- int player_pos;
- int fame_pos;
+ case 1: size = fame_list_size_smith; list = smith_fame_list; break;
+ case 2: size = fame_list_size_chemist; list = chemist_fame_list; break;
+ case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break;
+ default: size = 0; list = NULL; break;
+ }
- switch(type)
- {
- case 1: size = fame_list_size_smith; list = smith_fame_list; break;
- case 2: size = fame_list_size_chemist; list = chemist_fame_list; break;
- case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break;
- default: size = 0; list = NULL; break;
- }
+ ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
+ ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
- ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
- ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be
-
- if( player_pos == size && fame_pos == size )
- ;// not on list and not enough fame to get on it
- else if( fame_pos == player_pos )
- {// same position
- list[player_pos].fame = fame;
- char_update_fame_list(type, player_pos, fame);
+ if( player_pos == size && fame_pos == size )
+ ;// not on list and not enough fame to get on it
+ else if( fame_pos == player_pos )
+ {// same position
+ list[player_pos].fame = fame;
+ char_update_fame_list(type, player_pos, fame);
+ }
+ else
+ {// move in the list
+ if( player_pos == size )
+ {// new ranker - not in the list
+ ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
+ list[fame_pos].id = cid;
+ list[fame_pos].fame = fame;
+ char_loadName(cid, list[fame_pos].name);
}
else
- {// move in the list
- if( player_pos == size )
- {// new ranker - not in the list
- ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
- list[fame_pos].id = cid;
- list[fame_pos].fame = fame;
- char_loadName(cid, list[fame_pos].name);
- }
- else
- {// already in the list
- if( fame_pos == size )
- --fame_pos;// move to the end of the list
- ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
- list[fame_pos].fame = fame;
- }
- char_send_fame_list(-1);
+ {// already in the list
+ if( fame_pos == size )
+ --fame_pos;// move to the end of the list
+ ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
+ list[fame_pos].fame = fame;
}
-
- RFIFOSKIP(fd,11);
+ char_send_fame_list(-1);
}
- break;
- // Divorce chars
- case 0x2b11:
- if( RFIFOREST(fd) < 10 )
- return 0;
- divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
- RFIFOSKIP(fd,10);
- break;
+ RFIFOSKIP(fd,11);
+ }
+ return 1;
+}
- case 0x2b16: // Receive rates [Wizputer]
- if( RFIFOREST(fd) < 14 )
- return 0;
- {
- char esc_server_name[sizeof(server_name)*2+1];
+int char_parsemap_reqdivorce(int fd, int id){
+ if( RFIFOREST(fd) < 10 )
+ return 0;
+ divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6));
+ RFIFOSKIP(fd,10);
+ return 1;
+}
+int char_parsemap_updmapinfo(int fd, int id){
+ if( RFIFOREST(fd) < 14 )
+ return 0;
+ {
+ char esc_server_name[sizeof(server_name)*2+1];
- Sql_EscapeString(sql_handle, esc_server_name, server_name);
+ Sql_EscapeString(sql_handle, esc_server_name, server_name);
- if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
- ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
- Sql_ShowDebug(sql_handle);
- RFIFOSKIP(fd,14);
- }
- break;
+ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
+ ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
+ Sql_ShowDebug(sql_handle);
+ RFIFOSKIP(fd,14);
+ }
+ return 1;
+}
+int char_parsemap_setcharoffline(int fd, int id){
+ if (RFIFOREST(fd) < 6)
+ return 0;
+ set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
+ RFIFOSKIP(fd,10);
+ return 1;
+}
+int char_parsemap_setalloffline(int fd, int id){
+ set_all_offline(id);
+ RFIFOSKIP(fd,2);
+ return 1;
+}
+int char_parsemap_setcharonline(int fd, int id){
+ if (RFIFOREST(fd) < 10)
+ return 0;
+ set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
+ RFIFOSKIP(fd,10);
+ return 1;
+}
+int char_parsemap_reqfamelist(int fd, int id){
+ if (RFIFOREST(fd) < 2)
+ return 0;
+ char_read_fame_list();
+ char_send_fame_list(-1);
+ RFIFOSKIP(fd,2);
+ return 1;
+}
- case 0x2b17: // Character disconnected set online 0 [Wizputer]
- if (RFIFOREST(fd) < 6)
- return 0;
- set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
- RFIFOSKIP(fd,10);
- break;
+int char_parsemap_save_scdata(int fd, int id){
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ {
+#ifdef ENABLE_SC_SAVING
+ int count, aid, cid;
- case 0x2b18: // Reset all chars to offline [Wizputer]
- set_all_offline(id);
- RFIFOSKIP(fd,2);
- break;
+ aid = RFIFOL(fd, 4);
+ cid = RFIFOL(fd, 8);
+ count = RFIFOW(fd, 12);
- case 0x2b19: // Character set online [Wizputer]
- if (RFIFOREST(fd) < 10)
- return 0;
- set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
- RFIFOSKIP(fd,10);
- break;
-
- case 0x2b1a: // Build and send fame ranking lists [DracoRPG]
- if (RFIFOREST(fd) < 2)
- return 0;
- char_read_fame_list();
- char_send_fame_list(-1);
- RFIFOSKIP(fd,2);
- break;
-
- case 0x2b1c: //Request to save status change data. [Skotlex]
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
+ if( count > 0 )
{
-#ifdef ENABLE_SC_SAVING
- int count, aid, cid;
+ struct status_change_data data;
+ StringBuf buf;
+ int i;
- aid = RFIFOL(fd, 4);
- cid = RFIFOL(fd, 8);
- count = RFIFOW(fd, 12);
-
- if( count > 0 )
+ StringBuf_Init(&buf);
+ StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
+ for( i = 0; i < count; ++i )
{
- struct status_change_data data;
- StringBuf buf;
- int i;
-
- StringBuf_Init(&buf);
- StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
- for( i = 0; i < count; ++i )
- {
- memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
- if( i > 0 )
- StringBuf_AppendStr(&buf, ", ");
- StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
- data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
- }
- if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
- Sql_ShowDebug(sql_handle);
- StringBuf_Destroy(&buf);
+ memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
+ if( i > 0 )
+ StringBuf_AppendStr(&buf, ", ");
+ StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid,
+ data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
}
+ if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
+ Sql_ShowDebug(sql_handle);
+ StringBuf_Destroy(&buf);
+ }
#endif
- RFIFOSKIP(fd, RFIFOW(fd, 2));
- }
- break;
+ RFIFOSKIP(fd, RFIFOW(fd, 2));
+ }
+ return 1;
+}
- case 0x2b23: // map-server alive packet
- WFIFOHEAD(fd,2);
- WFIFOW(fd,0) = 0x2b24;
- WFIFOSET(fd,2);
- RFIFOSKIP(fd,2);
- break;
+int char_parsemap_keepalive(int fd, int id){
+ WFIFOHEAD(fd,2);
+ WFIFOW(fd,0) = 0x2b24;
+ WFIFOSET(fd,2);
+ RFIFOSKIP(fd,2);
+ return 1;
+}
- case 0x2b26: // auth request from map-server
- if (RFIFOREST(fd) < 19)
- return 0;
+int char_parsemap_reqauth(int fd, int id){
+ if (RFIFOREST(fd) < 19)
+ return 0;
- {
- int account_id;
- int char_id;
- int login_id1;
- char sex;
- uint32 ip;
- struct auth_node* node;
- struct mmo_charstatus* cd;
- struct mmo_charstatus char_dat;
+ {
+ int account_id;
+ int char_id;
+ int login_id1;
+ char sex;
+ uint32 ip;
+ struct auth_node* node;
+ struct mmo_charstatus* cd;
+ struct mmo_charstatus char_dat;
- account_id = RFIFOL(fd,2);
- char_id = RFIFOL(fd,6);
- login_id1 = RFIFOL(fd,10);
- sex = RFIFOB(fd,14);
- ip = ntohl(RFIFOL(fd,15));
- RFIFOSKIP(fd,19);
+ account_id = RFIFOL(fd,2);
+ char_id = RFIFOL(fd,6);
+ login_id1 = RFIFOL(fd,10);
+ sex = RFIFOB(fd,14);
+ ip = ntohl(RFIFOL(fd,15));
+ RFIFOSKIP(fd,19);
- node = (struct auth_node*)idb_get(auth_db, account_id);
+ node = (struct auth_node*)idb_get(auth_db, account_id);
+ cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
+ if( cd == NULL )
+ { //Really shouldn't happen.
+ mmo_char_fromsql(char_id, &char_dat, true);
cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
- if( cd == NULL )
- { //Really shouldn't happen.
- mmo_char_fromsql(char_id, &char_dat, true);
- cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
- }
- if( runflag == CHARSERVER_ST_RUNNING &&
- cd != NULL &&
- node != NULL &&
- node->account_id == account_id &&
- node->char_id == char_id &&
- node->login_id1 == login_id1 &&
- node->sex == sex /*&&
- node->ip == ip*/ )
- {// auth ok
- cd->sex = sex;
+ }
+ if( runflag == CHARSERVER_ST_RUNNING &&
+ cd != NULL &&
+ node != NULL &&
+ node->account_id == account_id &&
+ node->char_id == char_id &&
+ node->login_id1 == login_id1 &&
+ node->sex == sex /*&&
+ node->ip == ip*/ )
+ {// auth ok
+ cd->sex = sex;
- WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
- WFIFOW(fd,0) = 0x2afd;
- WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
- WFIFOL(fd,4) = account_id;
- WFIFOL(fd,8) = node->login_id1;
- WFIFOL(fd,12) = node->login_id2;
- WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
- WFIFOL(fd,20) = node->group_id;
- WFIFOB(fd,24) = node->changing_mapservers;
- memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
- WFIFOSET(fd, WFIFOW(fd,2));
+ WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
+ WFIFOW(fd,0) = 0x2afd;
+ WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
+ WFIFOL(fd,4) = account_id;
+ WFIFOL(fd,8) = node->login_id1;
+ WFIFOL(fd,12) = node->login_id2;
+ WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT"
+ WFIFOL(fd,20) = node->group_id;
+ WFIFOB(fd,24) = node->changing_mapservers;
+ memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
+ WFIFOSET(fd, WFIFOW(fd,2));
- // only use the auth once and mark user online
- idb_remove(auth_db, account_id);
- set_char_online(id, char_id, account_id);
- }
- else
- {// auth failed
- WFIFOHEAD(fd,19);
- WFIFOW(fd,0) = 0x2b27;
- WFIFOL(fd,2) = account_id;
- WFIFOL(fd,6) = char_id;
- WFIFOL(fd,10) = login_id1;
- WFIFOB(fd,14) = sex;
- WFIFOL(fd,15) = htonl(ip);
- WFIFOSET(fd,19);
- }
+ // only use the auth once and mark user online
+ idb_remove(auth_db, account_id);
+ set_char_online(id, char_id, account_id);
}
- break;
+ else
+ {// auth failed
+ WFIFOHEAD(fd,19);
+ WFIFOW(fd,0) = 0x2b27;
+ WFIFOL(fd,2) = account_id;
+ WFIFOL(fd,6) = char_id;
+ WFIFOL(fd,10) = login_id1;
+ WFIFOB(fd,14) = sex;
+ WFIFOL(fd,15) = htonl(ip);
+ WFIFOSET(fd,19);
+ }
+ }
+ return 1;
+}
- case 0x2736: // ip address update
- if (RFIFOREST(fd) < 6) return 0;
- server[id].ip = ntohl(RFIFOL(fd, 2));
- ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
- RFIFOSKIP(fd,6);
- break;
+int char_parsemap_updmapip(int fd, int id){
+ if (RFIFOREST(fd) < 6) return 0;
+ server[id].ip = ntohl(RFIFOL(fd, 2));
+ ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip));
+ RFIFOSKIP(fd,6);
+ return 1;
+}
- case 0x3008:
- if( RFIFOREST(fd) < RFIFOW(fd,4) )
- return 0;/* packet wasn't fully received yet (still fragmented) */
- else {
- int sfd;/* stat server fd */
- 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 */
+int char_parsemap_fw_configstats(int fd, int id){
+ if( RFIFOREST(fd) < RFIFOW(fd,4) )
+ return 0;/* packet wasn't fully received yet (still fragmented) */
+ else {
+ int sfd;/* stat server fd */
+ 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 */
- if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
- RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
- break;/* connection not possible, we drop the report */
- }
-
- session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
- WFIFOHEAD(sfd, RFIFOW(fd,2) );
- memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
- WFIFOSET(sfd, RFIFOW(fd,2) );
- flush_fifo(sfd);
- do_close(sfd);
- RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
+ if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true,10) ) == -1 ) {
+ RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
+ return 0;/* connection not possible, we drop the report */
}
- break;
+ session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */
+ WFIFOHEAD(sfd, RFIFOW(fd,2) );
+ memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2));
+ WFIFOSET(sfd, RFIFOW(fd,2) );
+ flush_fifo(sfd);
+ do_close(sfd);
+ RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
+ }
+ return 1;
+}
+
+int parse_frommap(int fd){
+ int id; //mapserv id
+ ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
+ if( id == ARRAYLENGTH(server) )
+ {// not a map server
+ ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd);
+ do_close(fd);
+ return 0;
+ }
+ if( session[fd]->flag.eof )
+ {
+ do_close(fd);
+ server[id].fd = -1;
+ mapif_on_disconnect(id);
+ return 0;
+ }
+
+ while(RFIFOREST(fd) >= 2){
+ switch(RFIFOW(fd,0)){
+ // Receiving map names list from the map-server
+ case 0x2afa: char_parsemap_getmapname(fd,id); break;
+ //Packet command is now used for sc_data request. [Skotlex]
+ case 0x2afc: char_parsemap_askscdata(fd,id); break;
+ //MAP user count
+ case 0x2afe: char_parsemap_getusercount(fd,id); break; //get nb user
+ case 0x2aff: char_parsemap_regmapuser(fd,id); break; //register users
+ // Receive character data from map-server for saving
+ case 0x2b01: char_parsemap_reqsavechar(fd,id); break;
+ // req char selection;
+ case 0x2b02: char_parsemap_authok(fd,id); break;
+ // request "change map server"
+ case 0x2b05: char_parsemap_reqchangemapserv(fd,id); break;
+ // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind]
+ case 0x2b07: char_parsemap_askrmfriend(fd,id); break;
+ // char name request
+ case 0x2b08: char_parsemap_reqcharname(fd,id); break;
+ // Map server send information to change an email of an account -> login-server
+ case 0x2b0c: char_parsemap_reqnewemail(fd,id); break;
+ // Request from map-server to change an account's status (will just be forwarded to login server)
+ case 0x2b0e: char_parsemap_fwlog_changestatus(fd,id); break;
+ // Update and send fame ranking list
+ case 0x2b10: char_parsemap_updfamelist(fd,id); break;
+ // Divorce chars
+ case 0x2b11: char_parsemap_reqdivorce(fd,id); break;
+ // Receive rates [Wizputer]
+ case 0x2b16: char_parsemap_updmapinfo(fd,id); break;
+ // Character disconnected set online 0 [Wizputer]
+ case 0x2b17: char_parsemap_setcharoffline(fd,id); break;
+ // Reset all chars to offline [Wizputer]
+ case 0x2b18: char_parsemap_setalloffline(fd,id); break;
+ // Character set online [Wizputer]
+ case 0x2b19: char_parsemap_setcharonline(fd,id); break;
+ // Build and send fame ranking lists [DracoRPG]
+ case 0x2b1a: char_parsemap_reqfamelist(fd,id); break;
+ //Request to save status change data. [Skotlex]
+ case 0x2b1c: char_parsemap_save_scdata(fd,id); break;
+ // map-server alive packet
+ case 0x2b23: char_parsemap_keepalive(fd,id); break;
+ // auth request from map-server
+ case 0x2b26: char_parsemap_reqauth(fd,id); break;
+ // ip address update
+ case 0x2736: char_parsemap_updmapip(fd,id); break;
+ // transmit emu usage for anom stats
+ case 0x3008: char_parsemap_fw_configstats(fd,id); break;
default:
{
// inter server - packet
int r = inter_parse_frommap(fd);
if (r == 1) break; // processed
if (r == 2) return 0; // need more packet
-
// no inter server packet. no char server packet -> disconnect
ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
set_eof(fd);
@@ -3513,64 +3264,10 @@
return 0;
}
-void do_init_mapif(void)
-{
- int i;
- for( i = 0; i < ARRAYLENGTH(server); ++i )
- mapif_server_init(i);
-}
+//
+// Client IF
+//
-void do_final_mapif(void)
-{
- int i;
- for( i = 0; i < ARRAYLENGTH(server); ++i )
- mapif_server_destroy(i);
-}
-
-// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
-// If found, returns the server's index in the 'server' array (otherwise returns -1).
-int search_mapserver(unsigned short map, uint32 ip, uint16 port)
-{
- int i, j;
-
- for(i = 0; i < ARRAYLENGTH(server); i++)
- {
- if (server[i].fd > 0
- && (ip == (uint32)-1 || server[i].ip == ip)
- && (port == (uint16)-1 || server[i].port == port))
- {
- for (j = 0; server[i].map[j]; j++)
- if (server[i].map[j] == map)
- return i;
- }
- }
-
- return -1;
-}
-
-// Initialization process (currently only initialization inter_mapif)
-static int char_mapif_init(int fd)
-{
- return inter_mapif_init(fd);
-}
-
-//--------------------------------------------
-// Test to know if an IP come from LAN or WAN.
-//--------------------------------------------
-int lan_subnetcheck(uint32 ip)
-{
- int i;
- ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
- if( i < subnet_count ) {
- 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));
- return subnet[i].map_ip;
- } else {
- ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip));
- return 0;
- }
-}
-
-
/// @param result
/// 0 (0x718): An unknown error has occurred.
/// 1: none/success
@@ -3588,7 +3285,6 @@
WFIFOSET(fd,14);
}
-
/// @param result
/// 0 (0x718): An unknown error has occurred.
/// 1: none/success
@@ -3606,7 +3302,6 @@
WFIFOSET(fd,10);
}
-
/// @param result
/// 1 (0x718): none/success, (if char id not in deletion process): An unknown error has occurred.
/// 2 (0x719): A database error occurred.
@@ -3620,34 +3315,37 @@
WFIFOSET(fd,10);
}
-
-static void char_delete2_req(int fd, struct char_session_data* sd)
-{// CH: <0827>.W <char id>.L
+// CH: <0827>.W <char id>.L
+int char_parse_delete2_req(int fd, struct char_session_data* sd)
+{
int char_id, i;
char* data;
time_t delete_date;
+ FIFOSD_CHECK(6)
+
char_id = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
if( i == MAX_CHARS )
{// character not found
char_delete2_ack(fd, char_id, 3, 0);
- return;
+ return 0;
}
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) )
{
Sql_ShowDebug(sql_handle);
char_delete2_ack(fd, char_id, 3, 0);
- return;
+ return 0;
}
Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10);
if( delete_date ) {// character already queued for deletion
char_delete2_ack(fd, char_id, 0, 0);
- return;
+ return 0;
}
/*
@@ -3674,14 +3372,14 @@
{
Sql_ShowDebug(sql_handle);
char_delete2_ack(fd, char_id, 3, 0);
- return;
+ return 0;
}
char_delete2_ack(fd, char_id, 1, delete_date);
+ return 1;
}
-
-static void char_delete2_accept(int fd, struct char_session_data* sd)
+int char_parse_delete2_accept(int fd, struct char_session_data* sd)
{// CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
char birthdate[8+1];
int char_id, i, k;
@@ -3689,6 +3387,8 @@
char* data;
time_t delete_date;
+ FIFOSD_CHECK(12)
+
char_id = RFIFOL(fd,2);
ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id);
@@ -3703,19 +3403,20 @@
birthdate[6] = RFIFOB(fd,10);
birthdate[7] = RFIFOB(fd,11);
birthdate[8] = 0;
+ RFIFOSKIP(fd,12);
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
if( i == MAX_CHARS )
{// character not found
char_delete2_accept_ack(fd, char_id, 3);
- return;
+ return 0;
}
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) )
{// data error
Sql_ShowDebug(sql_handle);
char_delete2_accept_ack(fd, char_id, 3);
- return;
+ return 0;
}
Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10);
@@ -3724,26 +3425,26 @@
if( !delete_date || delete_date>time(NULL) )
{// not queued or delay not yet passed
char_delete2_accept_ack(fd, char_id, 4);
- return;
+ return 0;
}
if( strcmp(sd->birthdate+2, birthdate) ) // +2 to cut off the century
{// birth date is wrong
char_delete2_accept_ack(fd, char_id, 5);
- return;
+ return 0;
}
if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) )
{// character level config restriction
char_delete2_accept_ack(fd, char_id, 2);
- return;
+ return 0;
}
// success
if( delete_char_sql(char_id) < 0 )
{
char_delete2_accept_ack(fd, char_id, 3);
- return;
+ return 0;
}
// refresh character list cache
@@ -3754,20 +3455,24 @@
sd->found_char[MAX_CHARS-1] = -1;
char_delete2_accept_ack(fd, char_id, 1);
+ return 1;
}
-
-static void char_delete2_cancel(int fd, struct char_session_data* sd)
-{// CH: <082b>.W <char id>.L
+// CH: <082b>.W <char id>.L
+int char_parse_delete2_cancel(int fd, struct char_session_data* sd)
+{
int char_id, i;
+ FIFOSD_CHECK(6)
+
char_id = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
if( i == MAX_CHARS )
{// character not found
char_delete2_cancel_ack(fd, char_id, 2);
- return;
+ return 0;
}
// there is no need to check, whether or not the character was
@@ -3777,637 +3482,52 @@
{
Sql_ShowDebug(sql_handle);
char_delete2_cancel_ack(fd, char_id, 2);
- return;
+ return 0;
}
char_delete2_cancel_ack(fd, char_id, 1);
+ return 1;
}
+int char_parse_maplogin(int fd){
+ int i;
-int parse_char(int fd)
-{
- int i, ch;
- char email[40];
- unsigned short cmd;
- int map_fd;
- struct char_session_data* sd;
- uint32 ipl = session[fd]->client_addr;
-
- sd = (struct char_session_data*)session[fd]->session_data;
-
- // disconnect any player if no login-server.
- if(login_fd < 0)
- set_eof(fd);
-
- if(session[fd]->flag.eof)
- {
- if( sd != NULL && sd->auth )
- { // already authed client
- struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
- if( data != NULL && data->fd == fd)
- data->fd = -1;
- if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
- set_char_offline(-1,sd->account_id);
- }
- do_close(fd);
+ if (RFIFOREST(fd) < 60)
return 0;
- }
-
- while( RFIFOREST(fd) >= 2 )
- {
- //For use in packets that depend on an sd being present [Skotlex]
- #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
-
- cmd = RFIFOW(fd,0);
- switch( cmd )
+ else {
+ char* l_user = (char*)RFIFOP(fd,2);
+ char* l_pass = (char*)RFIFOP(fd,26);
+ l_user[23] = '\0';
+ l_pass[23] = '\0';
+ ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
+ if( runflag != CHARSERVER_ST_RUNNING ||
+ i == ARRAYLENGTH(server) ||
+ strcmp(l_user, userid) != 0 ||
+ strcmp(l_pass, passwd) != 0 )
{
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x2af9;
+ WFIFOB(fd,2) = 3;
+ WFIFOSET(fd,3);
+ } else {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x2af9;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
- // request to connect
- // 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
- case 0x65:
- if( RFIFOREST(fd) < 17 )
- return 0;
- {
- struct auth_node* node;
-
- int account_id = RFIFOL(fd,2);
- uint32 login_id1 = RFIFOL(fd,6);
- uint32 login_id2 = RFIFOL(fd,10);
- int sex = RFIFOB(fd,16);
- RFIFOSKIP(fd,17);
-
- ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
-
- if (sd) {
- //Received again auth packet for already authentified account?? Discard it.
- //TODO: Perhaps log this as a hack attempt?
- //TODO: and perhaps send back a reply?
- break;
- }
-
- CREATE(session[fd]->session_data, struct char_session_data, 1);
- sd = (struct char_session_data*)session[fd]->session_data;
- sd->account_id = account_id;
- sd->login_id1 = login_id1;
- sd->login_id2 = login_id2;
- sd->sex = sex;
- sd->auth = false; // not authed yet
-
- // send back account_id
- WFIFOHEAD(fd,4);
- WFIFOL(fd,0) = account_id;
- WFIFOSET(fd,4);
-
- if( runflag != CHARSERVER_ST_RUNNING )
- {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0;// rejected from server
- WFIFOSET(fd,3);
- break;
- }
-
- // search authentification
- node = (struct auth_node*)idb_get(auth_db, account_id);
- if( node != NULL &&
- node->account_id == account_id &&
- node->login_id1 == login_id1 &&
- node->login_id2 == login_id2 /*&&
- node->ip == ipl*/ )
- {// authentication found (coming from map server)
- idb_remove(auth_db, account_id);
- char_auth_ok(fd, sd);
- }
- else
- {// authentication not found (coming from login server)
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd,23);
- WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
- WFIFOL(login_fd,2) = sd->account_id;
- WFIFOL(login_fd,6) = sd->login_id1;
- WFIFOL(login_fd,10) = sd->login_id2;
- WFIFOB(login_fd,14) = sd->sex;
- WFIFOL(login_fd,15) = htonl(ipl);
- WFIFOL(login_fd,19) = fd;
- WFIFOSET(login_fd,23);
- } else { // if no login-server, we must refuse connection
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- }
- }
+ server[i].fd = fd;
+ server[i].ip = ntohl(RFIFOL(fd,54));
+ server[i].port = ntohs(RFIFOW(fd,58));
+ server[i].users = 0;
+ memset(server[i].map, 0, sizeof(server[i].map));
+ session[fd]->func_parse = parse_frommap;
+ session[fd]->flag.server = 1;
+ realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
+ char_mapif_init(fd);
}
- break;
-
- // char select
- case 0x66:
- FIFOSD_CHECK(3);
- {
- struct mmo_charstatus char_dat;
- struct mmo_charstatus *cd;
- char* data;
- int char_id;
- uint32 subnet_map_ip;
- struct auth_node* node;
-
- int slot = RFIFOB(fd,2);
- RFIFOSKIP(fd,3);
-
- 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)
- || SQL_SUCCESS != Sql_NextRow(sql_handle)
- || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
- { //Not found?? May be forged packet.
- Sql_ShowDebug(sql_handle);
- Sql_FreeResult(sql_handle);
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0; // rejected from server
- WFIFOSET(fd,3);
- break;
- }
-
- char_id = atoi(data);
- Sql_FreeResult(sql_handle);
-
- /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
- set_char_online(-2,char_id,sd->account_id);
- if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
- set_char_offline(char_id, sd->account_id);
- /* failed to load something. REJECT! */
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- break;/* jump off this boat */
- }
-
- //Have to switch over to the DB instance otherwise data won't propagate [Kevin]
- cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
- cd->sex = sd->sex;
-
- if (log_char) {
- char esc_name[NAME_LENGTH*2+1];
-
- Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
- if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
- charlog_db, sd->account_id, slot, esc_name) )
- Sql_ShowDebug(sql_handle);
- }
- ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
-
- // searching map server
- i = search_mapserver(cd->last_point.map, -1, -1);
-
- // if map is not found, we check major cities
- if (i < 0 || !cd->last_point.map) {
- unsigned short j;
- //First check that there's actually a map server online.
- ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
- if (j == ARRAYLENGTH(server)) {
- ShowInfo("Connection Closed. No map servers available.\n");
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
- if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
- cd->last_point.x = 273;
- cd->last_point.y = 354;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
- cd->last_point.x = 120;
- cd->last_point.y = 100;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
- cd->last_point.x = 160;
- cd->last_point.y = 94;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
- cd->last_point.x = 116;
- cd->last_point.y = 57;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
- cd->last_point.x = 87;
- cd->last_point.y = 117;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
- cd->last_point.x = 94;
- cd->last_point.y = 103;
- } else {
- 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));
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
- ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
- cd->last_point.map = j;
- }
-
- //Send NEW auth packet [Kevin]
- //FIXME: is this case even possible? [ultramage]
- if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
- {
- ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
- server[i].fd = -1;
- memset(&server[i], 0, sizeof(struct mmo_map_server));
- //Send server closed.
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
-
- //Send player to map
- WFIFOHEAD(fd,28);
- WFIFOW(fd,0) = 0x71;
- WFIFOL(fd,2) = cd->char_id;
- mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
- subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
- WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
- WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
- WFIFOSET(fd,28);
-
- // create temporary auth entry
- CREATE(node, struct auth_node, 1);
- node->account_id = sd->account_id;
- node->char_id = cd->char_id;
- node->login_id1 = sd->login_id1;
- node->login_id2 = sd->login_id2;
- node->sex = sd->sex;
- node->expiration_time = sd->expiration_time;
- node->group_id = sd->group_id;
- node->ip = ipl;
- idb_put(auth_db, sd->account_id, node);
-
- }
- break;
-
- // create new char
-#if PACKETVER >= 20120307
- // S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
- case 0x970:
- FIFOSD_CHECK(31);
-#else
- // S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
- case 0x67:
- FIFOSD_CHECK(37);
-#endif
-
- if( !char_new ) //turn character creation on/off [Kevin]
- i = -2;
- else
-#if PACKETVER >= 20120307
- i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
-#else
- 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));
-#endif
-
- //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
- if (i < 0) {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6e;
- /* Others I found [Ind] */
- /* 0x02 = Symbols in Character Names are forbidden */
- /* 0x03 = You are not elegible to open the Character Slot. */
- switch (i) {
- case -1: WFIFOB(fd,2) = 0x00; break;
- case -2: WFIFOB(fd,2) = 0xFF; break;
- case -3: WFIFOB(fd,2) = 0x01; break;
- case -4: WFIFOB(fd,2) = 0x03; break;
- }
- WFIFOSET(fd,3);
- } else {
- int len;
- // retrieve data
- struct mmo_charstatus char_dat;
- mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
-
- // send to player
- WFIFOHEAD(fd,2+MAX_CHAR_BUF);
- WFIFOW(fd,0) = 0x6d;
- len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
- WFIFOSET(fd,len);
-
- // add new entry to the chars list
- ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
- if( ch < MAX_CHARS )
- sd->found_char[ch] = i; // the char_id of the new char
- }
-#if PACKETVER >= 20120307
- RFIFOSKIP(fd,31);
-#else
- RFIFOSKIP(fd,37);
-#endif
- break;
-
- // delete char
- case 0x68:
- // 2004-04-19aSakexe+ langtype 12 char deletion packet
- case 0x1fb:
- if (cmd == 0x68) FIFOSD_CHECK(46);
- if (cmd == 0x1fb) FIFOSD_CHECK(56);
- {
- int cid = RFIFOL(fd,2);
-
- ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
- memcpy(email, RFIFOP(fd,6), 40);
- RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
-
- // Check if e-mail is correct
- if(strcmpi(email, sd->email) && //email does not matches and
- (
- strcmp("[email protected]", sd->email) || //it is not default email, or
- (strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
- )) { //Fail
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x70;
- WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
- WFIFOSET(fd,3);
- break;
- }
-
- // check if this char exists
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- { // Such a character does not exist in the account
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x70;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- break;
- }
-
- // remove char from list and compact it
- for(ch = i; ch < MAX_CHARS-1; ch++)
- sd->found_char[ch] = sd->found_char[ch+1];
- sd->found_char[MAX_CHARS-1] = -1;
-
- /* Delete character */
- if(delete_char_sql(cid)<0){
- //can't delete the char
- //either SQL error or can't delete by some CONFIG conditions
- //del fail
- WFIFOHEAD(fd,3);
- WFIFOW(fd, 0) = 0x70;
- WFIFOB(fd, 2) = 0;
- WFIFOSET(fd, 3);
- break;
- }
- /* Char successfully deleted.*/
- WFIFOHEAD(fd,2);
- WFIFOW(fd,0) = 0x6f;
- WFIFOSET(fd,2);
- }
- break;
-
- // client keep-alive packet (every 12 seconds)
- // R 0187 <account ID>.l
- case 0x187:
- if (RFIFOREST(fd) < 6)
- return 0;
- RFIFOSKIP(fd,6);
- break;
- // char rename request
- // R 08fc <char ID>.l <new name>.24B
- case 0x8fc:
- FIFOSD_CHECK(30);
- {
- int i, cid =RFIFOL(fd,2);
- char name[NAME_LENGTH];
- char esc_name[NAME_LENGTH*2+1];
- safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH);
- RFIFOSKIP(fd,30);
-
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- break;
-
- normalize_name(name,TRIM_CHARS);
- Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
- if( !check_char_name(name,esc_name) ) {
- i = 1;
- safestrncpy(sd->new_name, name, NAME_LENGTH);
- } else
- i = 0;
-
- WFIFOHEAD(fd, 4);
- WFIFOW(fd,0) = 0x28e;
- WFIFOW(fd,2) = i;
- WFIFOSET(fd,4);
- }
- break;
-
- // char rename request
- // R 028d <account ID>.l <char ID>.l <new name>.24B
- case 0x28d:
- FIFOSD_CHECK(34);
- {
- int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6);
- char name[NAME_LENGTH];
- char esc_name[NAME_LENGTH*2+1];
- safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
- RFIFOSKIP(fd,34);
-
- if( aid != sd->account_id )
- break;
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- break;
-
- normalize_name(name,TRIM_CHARS);
- Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
- if( !check_char_name(name,esc_name) )
- {
- i = 1;
- safestrncpy(sd->new_name, name, NAME_LENGTH);
- }
- else
- i = 0;
-
- WFIFOHEAD(fd, 4);
- WFIFOW(fd,0) = 0x28e;
- WFIFOW(fd,2) = i;
- WFIFOSET(fd,4);
- }
- break;
- //Confirm change name.
- // 0x28f <char_id>.L
- case 0x28f:
- // 0: Sucessfull
- // 1: This character's name has already been changed. You cannot change a character's name more than once.
- // 2: User information is not correct.
- // 3: You have failed to change this character's name.
- // 4: Another user is using this character name, so please select another one.
- FIFOSD_CHECK(6);
- {
- int i;
- int cid = RFIFOL(fd,2);
- RFIFOSKIP(fd,6);
-
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- break;
- i = rename_char_sql(sd, cid);
-
- WFIFOHEAD(fd, 4);
- WFIFOW(fd,0) = 0x290;
- WFIFOW(fd,2) = i;
- WFIFOSET(fd,4);
- }
- break;
-
- // captcha code request (not implemented)
- // R 07e5 <?>.w <aid>.l
- case 0x7e5:
- WFIFOHEAD(fd,5);
- WFIFOW(fd,0) = 0x7e9;
- WFIFOW(fd,2) = 5;
- WFIFOB(fd,4) = 1;
- WFIFOSET(fd,5);
- RFIFOSKIP(fd,8);
- break;
-
- // captcha code check (not implemented)
- // R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
- case 0x7e7:
- WFIFOHEAD(fd,5);
- WFIFOW(fd,0) = 0x7e9;
- WFIFOW(fd,2) = 5;
- WFIFOB(fd,4) = 1;
- WFIFOSET(fd,5);
- RFIFOSKIP(fd,32);
- break;
-
- // deletion timer request
- case 0x827:
- FIFOSD_CHECK(6);
- char_delete2_req(fd, sd);
- RFIFOSKIP(fd,6);
- break;
-
- // deletion accept request
- case 0x829:
- FIFOSD_CHECK(12);
- char_delete2_accept(fd, sd);
- RFIFOSKIP(fd,12);
- break;
-
- // deletion cancel request
- case 0x82b:
- FIFOSD_CHECK(6);
- char_delete2_cancel(fd, sd);
- RFIFOSKIP(fd,6);
- break;
-
- // login as map-server
- case 0x2af8:
- if (RFIFOREST(fd) < 60)
- return 0;
- else {
- char* l_user = (char*)RFIFOP(fd,2);
- char* l_pass = (char*)RFIFOP(fd,26);
- l_user[23] = '\0';
- l_pass[23] = '\0';
- ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
- if( runflag != CHARSERVER_ST_RUNNING ||
- i == ARRAYLENGTH(server) ||
- strcmp(l_user, userid) != 0 ||
- strcmp(l_pass, passwd) != 0 )
- {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x2af9;
- WFIFOB(fd,2) = 3;
- WFIFOSET(fd,3);
- } else {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x2af9;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
-
- server[i].fd = fd;
- server[i].ip = ntohl(RFIFOL(fd,54));
- server[i].port = ntohs(RFIFOW(fd,58));
- server[i].users = 0;
- memset(server[i].map, 0, sizeof(server[i].map));
- session[fd]->func_parse = parse_frommap;
- session[fd]->flag.server = 1;
- realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
- char_mapif_init(fd);
- }
- RFIFOSKIP(fd,60);
- }
- return 0; // avoid processing of followup packets here
-
- // checks the entered pin
- case 0x8b8:
- if( RFIFOREST(fd) < 10 )
- return 0;
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
- pincode_check( fd, sd );
- RFIFOSKIP(fd,10);
- break;
-
- // request for PIN window
- case 0x8c5:
- if( RFIFOREST(fd) < 6 )
- return 0;
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
- if( strlen( sd->pincode ) <= 0 ){
- pincode_sendstate( fd, sd, PINCODE_NEW );
- }else{
- pincode_sendstate( fd, sd, PINCODE_ASK );
- }
- }
- RFIFOSKIP(fd,6);
- break;
-
- // pincode change request
- case 0x8be:
- if( RFIFOREST(fd) < 14 )
- return 0;
-
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
- pincode_change( fd, sd );
-
- RFIFOSKIP(fd,14);
- break;
-
- // activate PIN system and set first PIN
- case 0x8ba:
- if( RFIFOREST(fd) < 10 )
- return 0;
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
- pincode_setnew( fd, sd );
- RFIFOSKIP(fd,10);
- break;
-
- // character movement request
- case 0x8d4:
- if( RFIFOREST(fd) < 8 )
- return 0;
-
- moveCharSlot( fd, sd, RFIFOW(fd, 2), RFIFOW(fd, 4) );
- mmo_char_send(fd, sd);
- RFIFOSKIP(fd,8);
- break;
-
- case 0x9a1:
- if( RFIFOREST(fd) < 2 )
- return 0;
- char_parse_req_charlist(fd,sd);
- RFIFOSKIP(fd,2);
- break;
-
- // unknown packet received
- default:
- 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));
- set_eof(fd);
- return 0;
- }
+ RFIFOSKIP(fd,60);
}
-
- RFIFOFLUSH(fd);
- return 0;
+ return 1;
}
// Console Command Parser [Wizputer]
@@ -4563,53 +3683,84 @@
return 0;
}
-int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
-{
- if (login_fd > 0 && session[login_fd] != NULL)
- return 0;
+//------------------------------------------------
+//Pincode system
+//------------------------------------------------
- ShowInfo("Attempt to connect to login-server...\n");
- login_fd = make_connection(login_ip, login_port, false,10);
- if (login_fd == -1)
- { //Try again later. [Skotlex]
- login_fd = 0;
+/* pincode_sendstate transmist the pincode state to client
+ * S 08b9 <seed>.L <aid>.L <state>.W (HC_SECOND_PASSWD_LOGIN)
+ * state :
+ * 0 = disabled / pin is correct
+ * 1 = ask for pin - client sends 0x8b8
+ * 2 = create new pin - client sends 0x8ba
+ * 3 = pin must be changed - client 0x8be
+ * 4 = create new pin - client sends 0x8ba
+ * 5 = client shows msgstr(1896)
+ * 6 = client shows msgstr(1897) Unable to use your KSSN number
+ * 7 = char select window shows a button - client sends 0x8c5
+ * 8 = pincode was incorrect
+*/
+void pincode_sendstate( int fd, struct char_session_data* sd, enum pincode_state state ){
+ WFIFOHEAD(fd, 12);
+ WFIFOW(fd, 0) = 0x8b9;
+ WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
+ WFIFOL(fd, 6) = sd->account_id;
+ WFIFOW(fd,10) = state;
+ WFIFOSET(fd,12);
+}
+
+void pincode_notifyLoginPinError( int account_id ){
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x2739;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOSET(login_fd,6);
+}
+
+void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
+ WFIFOHEAD(login_fd,11);
+ WFIFOW(login_fd,0) = 0x2738;
+ WFIFOL(login_fd,2) = account_id;
+ strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
+ WFIFOSET(login_fd,11);
+}
+
+int char_parse_reqpincode_window(int fd, struct char_session_data* sd){
+ if( RFIFOREST(fd) < 6 )
return 0;
+ if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
+ if( strlen( sd->pincode ) <= 0 ){
+ pincode_sendstate( fd, sd, PINCODE_NEW );
+ }else{
+ pincode_sendstate( fd, sd, PINCODE_ASK );
+ }
}
- session[login_fd]->func_parse = parse_fromlogin;
- session[login_fd]->flag.server = 1;
- realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
-
- WFIFOHEAD(login_fd,86);
- WFIFOW(login_fd,0) = 0x2710;
- memcpy(WFIFOP(login_fd,2), userid, 24);
- memcpy(WFIFOP(login_fd,26), passwd, 24);
- WFIFOL(login_fd,50) = 0;
- WFIFOL(login_fd,54) = htonl(char_ip);
- WFIFOW(login_fd,58) = htons(char_port);
- memcpy(WFIFOP(login_fd,60), server_name, 20);
- WFIFOW(login_fd,80) = 0;
- WFIFOW(login_fd,82) = char_maintenance;
- WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
- WFIFOSET(login_fd,86);
-
+ RFIFOSKIP(fd,6);
return 1;
}
-//------------------------------------------------
-//Pincode system
-//------------------------------------------------
-void pincode_check( int fd, struct char_session_data* sd ){
- char pin[PINCODE_LENGTH+1];
+void pincode_decrypt( uint32 userSeed, char* pin ){
+ int i, pos;
+ char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ char *buf;
+ uint32 multiplier = 0x3498, baseSeed = 0x881234;
- memset(pin,0,PINCODE_LENGTH+1);
+ for( i = 1; i < 10; i++ ){
+ userSeed = baseSeed + userSeed * multiplier;
+ pos = userSeed % ( i + 1 );
+ if( i != pos ){
+ tab[i] ^= tab[pos];
+ tab[pos] ^= tab[i];
+ tab[i] ^= tab[pos];
+ }
+ }
- strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
-
- pincode_decrypt(sd->pincode_seed, pin );
-
- if( pincode_compare( fd, sd, pin ) ){
- pincode_sendstate( fd, sd, PINCODE_PASSED );
+ buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
+ memset( buf, 0, PINCODE_LENGTH + 1 );
+ for( i = 0; i < PINCODE_LENGTH; i++ ){
+ sprintf( buf + i, "%d", tab[pin[i] - '0'] );
}
+ strcpy( pin, buf );
+ free( buf );
}
int pincode_compare( int fd, struct char_session_data* sd, char* pin ){
@@ -4627,114 +3778,110 @@
}
}
-void pincode_change( int fd, struct char_session_data* sd ){
+int char_parse_pincode_check( int fd, struct char_session_data* sd ){
+ char pin[PINCODE_LENGTH+1];
+
+ if( RFIFOREST(fd) < 10 )
+ return 0;
+ if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
+ return 0;
+
+ memset(pin,0,PINCODE_LENGTH+1);
+ strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
+ RFIFOSKIP(fd,10);
+
+ pincode_decrypt(sd->pincode_seed, pin );
+ if( pincode_compare( fd, sd, pin ) ){
+ pincode_sendstate( fd, sd, PINCODE_PASSED );
+ }
+ return 1;
+}
+
+int char_parse_pincode_change( int fd, struct char_session_data* sd ){
char oldpin[PINCODE_LENGTH+1];
char newpin[PINCODE_LENGTH+1];
+ if( RFIFOREST(fd) < 14 )
+ return 0;
+ if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
+ return 0;
+
memset(oldpin,0,PINCODE_LENGTH+1);
memset(newpin,0,PINCODE_LENGTH+1);
+ strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
+ strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
+ RFIFOSKIP(fd,14);
- strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
pincode_decrypt(sd->pincode_seed,oldpin);
-
if( !pincode_compare( fd, sd, oldpin ) )
- return;
-
- strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
+ return 0;
pincode_decrypt(sd->pincode_seed,newpin);
pincode_notifyLoginPinUpdate( sd->account_id, newpin );
strncpy(sd->pincode, newpin, sizeof(newpin));
pincode_sendstate( fd, sd, PINCODE_PASSED );
+ return 1;
}
-void pincode_setnew( int fd, struct char_session_data* sd ){
+int char_parse_pincode_setnew( int fd, struct char_session_data* sd ){
char newpin[PINCODE_LENGTH+1];
memset(newpin,0,PINCODE_LENGTH+1);
+ if( RFIFOREST(fd) < 10 )
+ return 0;
+
+ if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
+ return 0;
strncpy( newpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH );
+ RFIFOSKIP(fd,10);
+
pincode_decrypt( sd->pincode_seed, newpin );
pincode_notifyLoginPinUpdate( sd->account_id, newpin );
strncpy( sd->pincode, newpin, strlen( newpin ) );
pincode_sendstate( fd, sd, PINCODE_PASSED );
+ return 1;
}
-// 0 = disabled / pin is correct
-// 1 = ask for pin - client sends 0x8b8
-// 2 = create new pin - client sends 0x8ba
-// 3 = pin must be changed - client 0x8be
-// 4 = create new pin - client sends 0x8ba
-// 5 = client shows msgstr(1896)
-// 6 = client shows msgstr(1897) Unable to use your KSSN number
-// 7 = char select window shows a button - client sends 0x8c5
-// 8 = pincode was incorrect
-void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state ){
- WFIFOHEAD(fd, 12);
- WFIFOW(fd, 0) = 0x8b9;
- WFIFOL(fd, 2) = sd->pincode_seed = rnd() % 0xFFFF;
- WFIFOL(fd, 6) = sd->account_id;
- WFIFOW(fd,10) = state;
- WFIFOSET(fd,12);
-}
-void pincode_notifyLoginPinUpdate( int account_id, char* pin ){
- WFIFOHEAD(login_fd,11);
- WFIFOW(login_fd,0) = 0x2738;
- WFIFOL(login_fd,2) = account_id;
- strncpy( (char*)WFIFOP(login_fd,6), pin, PINCODE_LENGTH+1 );
- WFIFOSET(login_fd,11);
+//------------------------------------------------
+//Add On system
+//------------------------------------------------
+// reason
+// 0: success
+// 1: failed
+void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
+ WFIFOHEAD(fd,8);
+ WFIFOW(fd,0) = 0x8d5;
+ WFIFOW(fd,2) = 8;
+ WFIFOW(fd,4) = reason;
+ WFIFOW(fd,6) = sd->char_moves[index];
+ WFIFOSET(fd,8);
}
-void pincode_notifyLoginPinError( int account_id ){
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x2739;
- WFIFOL(login_fd,2) = account_id;
- WFIFOSET(login_fd,6);
-}
+int char_parse_moveCharSlot( int fd, struct char_session_data* sd){
+ uint16 from, to;
-void pincode_decrypt( uint32 userSeed, char* pin ){
- int i, pos;
- char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- char *buf;
- uint32 multiplier = 0x3498, baseSeed = 0x881234;
+ if( RFIFOREST(fd) < 8 )
+ return 0;
+ from = RFIFOW(fd,2);
+ to = RFIFOW(fd,4);
+ //Cnt = RFIFOW(fd,6); //how many time we have left to change (client.. lol we don't trust him)
+ RFIFOSKIP(fd,8);
- for( i = 1; i < 10; i++ ){
- userSeed = baseSeed + userSeed * multiplier;
- pos = userSeed % ( i + 1 );
- if( i != pos ){
- tab[i] ^= tab[pos];
- tab[pos] ^= tab[i];
- tab[i] ^= tab[pos];
- }
- }
-
- buf = (char *)malloc( sizeof(char) * ( PINCODE_LENGTH + 1 ) );
- memset( buf, 0, PINCODE_LENGTH + 1 );
- for( i = 0; i < PINCODE_LENGTH; i++ ){
- sprintf( buf + i, "%d", tab[pin[i] - '0'] );
- }
- strcpy( pin, buf );
- free( buf );
-}
-
-//------------------------------------------------
-//Add On system
-//------------------------------------------------
-void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to ){
// Have we changed to often or is it disabled?
if( !char_move_enabled || ( !char_moves_unlimited && sd->char_moves[from] <= 0 ) ){
moveCharSlotReply( fd, sd, from, 1 );
- return;
+ return 0;
}
// We dont even have a character on the chosen slot?
if( sd->found_char[from] <= 0 ){
moveCharSlotReply( fd, sd, from, 1 );
- return;
+ return 0;
}
if( sd->found_char[to] > 0 ){
@@ -4749,17 +3896,17 @@
moveCharSlotReply( fd, sd, from, 1 );
Sql_ShowDebug(sql_handle);
Sql_QueryStr(sql_handle,"ROLLBACK");
- return;
+ return 0;
}
}else{
// Admin doesnt allow us to
moveCharSlotReply( fd, sd, from, 1 );
- return;
+ return 0;
}
}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] ) ){
Sql_ShowDebug(sql_handle);
moveCharSlotReply( fd, sd, from, 1 );
- return;
+ return 0;
}
if( !char_moves_unlimited ){
@@ -4770,20 +3917,9 @@
// We successfully moved the char - time to notify the client
moveCharSlotReply( fd, sd, from, 0 );
mmo_char_send(fd, sd);
+ return 1;
}
-// reason
-// 0: success
-// 1: failed
-void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
- WFIFOHEAD(fd,8);
- WFIFOW(fd,0) = 0x8d5;
- WFIFOW(fd,2) = 8;
- WFIFOW(fd,4) = reason;
- WFIFOW(fd,6) = sd->char_moves[index];
- WFIFOSET(fd,8);
-}
-
//------------------------------------------------
//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
//replies/disconnect the player we tried to kick. [Skotlex]
@@ -5154,6 +4290,989 @@
return 0;
}
+
+
+// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
+int char_parse_reqtoconnect(int fd, struct char_session_data* sd,uint32 ipl){
+ if( RFIFOREST(fd) < 17 ) // request to connect
+ return 0;
+ else {
+ struct auth_node* node;
+
+ int account_id = RFIFOL(fd,2);
+ uint32 login_id1 = RFIFOL(fd,6);
+ uint32 login_id2 = RFIFOL(fd,10);
+ int sex = RFIFOB(fd,16);
+ RFIFOSKIP(fd,17);
+
+ ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
+
+ if (sd) {
+ //Received again auth packet for already authentified account?? Discard it.
+ //TODO: Perhaps log this as a hack attempt?
+ //TODO: and perhaps send back a reply?
+ ShowInfo("Already registered break\n");
+ return 0;
+ }
+
+ CREATE(session[fd]->session_data, struct char_session_data, 1);
+ sd = (struct char_session_data*)session[fd]->session_data;
+ sd->account_id = account_id;
+ sd->login_id1 = login_id1;
+ sd->login_id2 = login_id2;
+ sd->sex = sex;
+ sd->auth = false; // not authed yet
+
+ // send back account_id
+ WFIFOHEAD(fd,4);
+ WFIFOL(fd,0) = account_id;
+ WFIFOSET(fd,4);
+
+ if( runflag != CHARSERVER_ST_RUNNING )
+ {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;// rejected from server
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ // search authentification
+ node = (struct auth_node*)idb_get(auth_db, account_id);
+ if( node != NULL &&
+ node->account_id == account_id &&
+ node->login_id1 == login_id1 &&
+ node->login_id2 == login_id2 /*&&
+ node->ip == ipl*/ )
+ {// authentication found (coming from map server)
+ ShowInfo("char_parse_reqtoconnect: authentication found (coming from map server)\n");
+ idb_remove(auth_db, account_id);
+ char_auth_ok(fd, sd);
+ }
+ else
+ {// authentication not found (coming from login server)
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd,23);
+ WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
+ WFIFOL(login_fd,2) = sd->account_id;
+ WFIFOL(login_fd,6) = sd->login_id1;
+ WFIFOL(login_fd,10) = sd->login_id2;
+ WFIFOB(login_fd,14) = sd->sex;
+ WFIFOL(login_fd,15) = htonl(ipl);
+ WFIFOL(login_fd,19) = fd;
+ WFIFOSET(login_fd,23);
+ } else { // if no login-server, we must refuse connection
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+ }
+ }
+ }
+ return 1;
+}
+
+int char_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
+ FIFOSD_CHECK(3);
+ {
+ struct mmo_charstatus char_dat;
+ struct mmo_charstatus *cd;
+ char* data;
+ int char_id;
+ uint32 subnet_map_ip;
+ struct auth_node* node;
+ int i, map_fd;
+
+ int slot = RFIFOB(fd,2);
+ RFIFOSKIP(fd,3);
+
+ 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)
+ || SQL_SUCCESS != Sql_NextRow(sql_handle)
+ || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
+ { //Not found?? May be forged packet.
+ Sql_ShowDebug(sql_handle);
+ Sql_FreeResult(sql_handle);
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0; // rejected from server
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ char_id = atoi(data);
+ Sql_FreeResult(sql_handle);
+
+ /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
+ set_char_online(-2,char_id,sd->account_id);
+ if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
+ set_char_offline(char_id, sd->account_id);
+ /* failed to load something. REJECT! */
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+ return 0;/* jump off this boat */
+ }
+
+ //Have to switch over to the DB instance otherwise data won't propagate [Kevin]
+ cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
+ cd->sex = sd->sex;
+
+ if (log_char) {
+ char esc_name[NAME_LENGTH*2+1];
+
+ Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
+ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
+ charlog_db, sd->account_id, slot, esc_name) )
+ Sql_ShowDebug(sql_handle);
+ }
+ ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
+
+ // searching map server
+ i = search_mapserver(cd->last_point.map, -1, -1);
+
+ // if map is not found, we check major cities
+ if (i < 0 || !cd->last_point.map) {
+ unsigned short j;
+ //First check that there's actually a map server online.
+ ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
+ if (j == ARRAYLENGTH(server)) {
+ ShowInfo("Connection Closed. No map servers available.\n");
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ return 0;
+ }
+ if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
+ cd->last_point.x = 273;
+ cd->last_point.y = 354;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
+ cd->last_point.x = 120;
+ cd->last_point.y = 100;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
+ cd->last_point.x = 160;
+ cd->last_point.y = 94;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
+ cd->last_point.x = 116;
+ cd->last_point.y = 57;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
+ cd->last_point.x = 87;
+ cd->last_point.y = 117;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
+ cd->last_point.x = 94;
+ cd->last_point.y = 103;
+ } else {
+ 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));
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ return 0;
+ }
+ ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
+ cd->last_point.map = j;
+ }
+
+ //Send NEW auth packet [Kevin]
+ //FIXME: is this case even possible? [ultramage]
+ if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
+ {
+ ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
+ server[i].fd = -1;
+ memset(&server[i], 0, sizeof(struct mmo_map_server));
+ //Send server closed.
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ //Send player to map
+ WFIFOHEAD(fd,28);
+ WFIFOW(fd,0) = 0x71;
+ WFIFOL(fd,2) = cd->char_id;
+ mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
+ subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
+ WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
+ WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
+ WFIFOSET(fd,28);
+
+ // create temporary auth entry
+ CREATE(node, struct auth_node, 1);
+ node->account_id = sd->account_id;
+ node->char_id = cd->char_id;
+ node->login_id1 = sd->login_id1;
+ node->login_id2 = sd->login_id2;
+ node->sex = sd->sex;
+ node->expiration_time = sd->expiration_time;
+ node->group_id = sd->group_id;
+ node->ip = ipl;
+ ShowInfo("Putting node into auth_db, node=%d, aid=%d, version=%d\n",
+ node,sd->account_id,sd->version);
+ idb_put(auth_db, sd->account_id, node);
+
+ }
+ return 1;
+}
+
+// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
+// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
+int char_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
+ int i=0, ch;
+
+ if (cmd == 0x970) FIFOSD_CHECK(31) //>=20120307
+ else if (cmd == 0x67) FIFOSD_CHECK(37)
+ else return 0;
+
+ if( !char_new ) //turn character creation on/off [Kevin]
+ i = -2;
+ else {
+ if (cmd == 0x970){
+ i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
+ RFIFOSKIP(fd,31);
+ }
+ else if(cmd == 0x67){
+#if PACKETVER < 20120307
+ 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));
+ RFIFOSKIP(fd,37);
+#endif
+ }
+ }
+
+ //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
+ if (i < 0) {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6e;
+ /* Others I found [Ind] */
+ /* 0x02 = Symbols in Character Names are forbidden */
+ /* 0x03 = You are not elegible to open the Character Slot. */
+ switch (i) {
+ case -1: WFIFOB(fd,2) = 0x00; break;
+ case -2: WFIFOB(fd,2) = 0xFF; break;
+ case -3: WFIFOB(fd,2) = 0x01; break;
+ case -4: WFIFOB(fd,2) = 0x03; break;
+ }
+ WFIFOSET(fd,3);
+ } else {
+ int len;
+ // retrieve data
+ struct mmo_charstatus char_dat;
+ mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
+
+ // send to player
+ WFIFOHEAD(fd,2+MAX_CHAR_BUF);
+ WFIFOW(fd,0) = 0x6d;
+ len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
+ WFIFOSET(fd,len);
+
+ // add new entry to the chars list
+ ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
+ if( ch < MAX_CHARS )
+ sd->found_char[ch] = i; // the char_id of the new char
+ }
+ return 1;
+}
+
+int char_parse_delchar(int fd,struct char_session_data* sd, int cmd){
+ char email[40];
+ int i, ch;
+
+ if (cmd == 0x68) FIFOSD_CHECK(46)
+ else if (cmd == 0x1fb) FIFOSD_CHECK(56)
+ else return 0;
+
+ {
+ int cid = RFIFOL(fd,2);
+
+ ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
+ memcpy(email, RFIFOP(fd,6), 40);
+ RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
+
+ // Check if e-mail is correct
+ if(strcmpi(email, sd->email) && //email does not matches and
+ (
+ strcmp("[email protected]", sd->email) || //it is not default email, or
+ (strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
+ )) { //Fail
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x70;
+ WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ // check if this char exists
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
+ if( i == MAX_CHARS )
+ { // Such a character does not exist in the account
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x70;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ // remove char from list and compact it
+ for(ch = i; ch < MAX_CHARS-1; ch++)
+ sd->found_char[ch] = sd->found_char[ch+1];
+ sd->found_char[MAX_CHARS-1] = -1;
+
+ /* Delete character */
+ if(delete_char_sql(cid)<0){
+ //can't delete the char
+ //either SQL error or can't delete by some CONFIG conditions
+ //del fail
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd, 0) = 0x70;
+ WFIFOB(fd, 2) = 0;
+ WFIFOSET(fd, 3);
+ return 0;
+ }
+ /* Char successfully deleted.*/
+ WFIFOHEAD(fd,2);
+ WFIFOW(fd,0) = 0x6f;
+ WFIFOSET(fd,2);
+ }
+ return 1;
+}
+
+// R 0187 <account ID>.l
+int char_parse_keepalive(int fd){
+ if (RFIFOREST(fd) < 6)
+ return 0;
+ //int aid = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
+ return 1;
+}
+
+// R 08fc <char ID>.l <new name>.24B
+// R 028d <account ID>.l <char ID>.l <new name>.24B
+int char_parse_reqrename(int fd, struct char_session_data* sd, int cmd){
+ if(cmd == 0x8fc) FIFOSD_CHECK(30)
+ if(cmd == 0x28d) FIFOSD_CHECK(34)
+ else return 0;
+
+ {
+ int i, cid=0;
+ char name[NAME_LENGTH];
+ char esc_name[NAME_LENGTH*2+1];
+ safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
+
+ if(cmd == 0x8fc){
+ cid =RFIFOL(fd,2);
+ RFIFOSKIP(fd,30);
+ }
+ else if(cmd == 0x28d) {
+ int aid = RFIFOL(fd,2);
+ cid =RFIFOL(fd,6);
+ if( aid != sd->account_id )
+ return 0;
+ RFIFOSKIP(fd,34);
+ }
+
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
+ if( i == MAX_CHARS )
+ return 0;
+
+ normalize_name(name,TRIM_CHARS);
+ Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
+ if( !check_char_name(name,esc_name) )
+ {
+ i = 1;
+ safestrncpy(sd->new_name, name, NAME_LENGTH);
+ }
+ else
+ i = 0;
+
+ WFIFOHEAD(fd, 4);
+ WFIFOW(fd,0) = 0x28e;
+ WFIFOW(fd,2) = i;
+ WFIFOSET(fd,4);
+ }
+ return 1;
+}
+
+// 0x28f <char_id>.L
+int char_parse_ackrename(int fd, struct char_session_data* sd){
+ // 0: Sucessfull
+ // 1: This character's name has already been changed. You cannot change a character's name more than once.
+ // 2: User information is not correct.
+ // 3: You have failed to change this character's name.
+ // 4: Another user is using this character name, so please select another one.
+ FIFOSD_CHECK(6)
+
+ {
+ int i;
+ int cid = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
+
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
+ if( i == MAX_CHARS )
+ return 0;
+ i = rename_char_sql(sd, cid);
+
+ WFIFOHEAD(fd, 4);
+ WFIFOW(fd,0) = 0x290;
+ WFIFOW(fd,2) = i;
+ WFIFOSET(fd,4);
+ }
+ return 1;
+}
+
+// R 07e5 <?>.w <aid>.l
+int char_parse_reqcaptcha(int fd){
+ WFIFOHEAD(fd,5);
+ WFIFOW(fd,0) = 0x7e9;
+ WFIFOW(fd,2) = 5;
+ WFIFOB(fd,4) = 1;
+ WFIFOSET(fd,5);
+ RFIFOSKIP(fd,8);
+ return 1;
+}
+
+// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
+int char_parse_chkcaptcha(int fd){
+ WFIFOHEAD(fd,5);
+ WFIFOW(fd,0) = 0x7e9;
+ WFIFOW(fd,2) = 5;
+ WFIFOB(fd,4) = 1;
+ WFIFOSET(fd,5);
+ RFIFOSKIP(fd,32);
+ return 1;
+}
+
+
+int parse_char(int fd)
+{
+ unsigned short cmd;
+ struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
+ uint32 ipl = session[fd]->client_addr;
+
+ // disconnect any player if no login-server.
+ if(login_fd < 0)
+ set_eof(fd);
+
+ if(session[fd]->flag.eof)
+ {
+ if( sd != NULL && sd->auth )
+ { // already authed client
+ struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
+ if( data != NULL && data->fd == fd)
+ data->fd = -1;
+ if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex]
+ set_char_offline(-1,sd->account_id);
+ }
+ do_close(fd);
+ return 0;
+ }
+
+ while( RFIFOREST(fd) >= 2 )
+ {
+ cmd = RFIFOW(fd,0);
+ switch( cmd )
+ {
+
+ case 0x65: char_parse_reqtoconnect(fd,sd,ipl); break;
+ // char select
+ case 0x66: char_parse_charselect(fd,sd,ipl); break;
+ // createnewchar
+ case 0x970: char_parse_createnewchar(fd,sd,cmd); break;
+ case 0x67: char_parse_createnewchar(fd,sd,cmd); break;
+ // delete char
+ case 0x68: char_parse_delchar(fd,sd,cmd); break; //
+ case 0x1fb: char_parse_delchar(fd,sd,cmd); break; // 2004-04-19aSakexe+ langtype 12 char deletion packet
+ // client keep-alive packet (every 12 seconds)
+ case 0x187: char_parse_keepalive(fd); break;
+ // char rename
+ case 0x8fc: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
+ case 0x28d: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
+ case 0x28f: char_parse_ackrename(fd,sd); break; //Confirm change name.
+ // captcha
+ case 0x7e5: char_parse_reqcaptcha(fd); break; // captcha code request (not implemented)
+ case 0x7e7: char_parse_chkcaptcha(fd); break; // captcha code check (not implemented)
+ // deletion timer request
+ case 0x827: char_parse_delete2_req(fd, sd); break;
+ // deletion accept request
+ case 0x829: char_parse_delete2_accept(fd, sd); break;
+ // deletion cancel request
+ case 0x82b: char_parse_delete2_cancel(fd, sd); break;
+ // login as map-server
+ case 0x2af8: char_parse_maplogin(fd); return 0; // avoid processing of followup packets here
+ //pincode
+ case 0x8b8: char_parse_pincode_check( fd, sd ); break; // checks the entered pin
+ case 0x8c5: char_parse_reqpincode_window(fd,sd); break; // request for PIN window
+ case 0x8be: char_parse_pincode_change( fd, sd ); break; // pincode change request
+ case 0x8ba: char_parse_pincode_setnew( fd, sd ); break; // activate PIN system and set first PIN
+ // character movement request
+ case 0x8d4: char_parse_moveCharSlot(fd,sd); break;
+ case 0x9a1: char_parse_req_charlist(fd,sd); break;
+ // unknown packet received
+ default:
+ 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));
+ set_eof(fd);
+ return 0;
+ }
+ }
+
+ RFIFOFLUSH(fd);
+ return 0;
+}
+
+///
+/// Login IF
+///
+
+int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
+{
+ if (login_fd > 0 && session[login_fd] != NULL)
+ return 0;
+
+ ShowInfo("Attempt to connect to login-server...\n");
+ login_fd = make_connection(login_ip, login_port, false,10);
+ if (login_fd == -1)
+ { //Try again later. [Skotlex]
+ login_fd = 0;
+ return 0;
+ }
+ session[login_fd]->func_parse = parse_fromlogin;
+ session[login_fd]->flag.server = 1;
+ realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
+
+ WFIFOHEAD(login_fd,86);
+ WFIFOW(login_fd,0) = 0x2710;
+ memcpy(WFIFOP(login_fd,2), userid, 24);
+ memcpy(WFIFOP(login_fd,26), passwd, 24);
+ WFIFOL(login_fd,50) = 0;
+ WFIFOL(login_fd,54) = htonl(char_ip);
+ WFIFOW(login_fd,58) = htons(char_port);
+ memcpy(WFIFOP(login_fd,60), server_name, 20);
+ WFIFOW(login_fd,80) = 0;
+ WFIFOW(login_fd,82) = char_maintenance;
+ WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
+ WFIFOSET(login_fd,86);
+
+ return 1;
+}
+
+int char_parselog_ackconnect(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 3)
+ return 0;
+
+ if (RFIFOB(fd,2)) {
+ //printf("connect login server error : %d\n", RFIFOB(fd,2));
+ ShowError("Can not connect to login-server.\n");
+ ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
+ ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
+ ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
+ set_eof(fd);
+ return 0;
+ } else {
+ ShowStatus("Connected to login-server (connection #%d).\n", fd);
+ loginif_on_ready();
+ }
+ RFIFOSKIP(fd,3);
+ return 1;
+}
+
+int char_parselog_ackaccreq(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 25)
+ return 0;
+ {
+ int account_id = RFIFOL(fd,2);
+ uint32 login_id1 = RFIFOL(fd,6);
+ uint32 login_id2 = RFIFOL(fd,10);
+ uint8 sex = RFIFOB(fd,14);
+ uint8 result = RFIFOB(fd,15);
+ int request_id = RFIFOL(fd,16);
+ uint32 version = RFIFOL(fd,20);
+ uint8 clienttype = RFIFOB(fd,24);
+ RFIFOSKIP(fd,25);
+
+ if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
+ !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
+ {
+ int client_fd = request_id;
+ sd->version = version;
+ sd->clienttype = clienttype;
+ switch( result )
+ {
+ case 0:// ok
+ char_auth_ok(client_fd, sd);
+ break;
+ case 1:// auth failed
+ WFIFOHEAD(client_fd,3);
+ WFIFOW(client_fd,0) = 0x6c;
+ WFIFOB(client_fd,2) = 0;// rejected from server
+ WFIFOSET(client_fd,3);
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+int char_parselog_reqaccdata(int fd, struct char_session_data* sd){
+ int i;
+ if (RFIFOREST(fd) < 73)
+ return 0;
+
+ // find the authenticated session with this account id
+ 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) );
+ if( i < fd_max )
+ {
+ int server_id;
+ memcpy(sd->email, RFIFOP(fd,6), 40);
+ sd->expiration_time = (time_t)RFIFOL(fd,46);
+ sd->group_id = RFIFOB(fd,50);
+ sd->char_slots = RFIFOB(fd,51);
+ if( sd->char_slots > MAX_CHARS ) {
+ 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);
+ sd->char_slots = MAX_CHARS;/* cap to maximum */
+ } else if ( !sd->char_slots )/* no value aka 0 in sql */
+ sd->char_slots = MAX_CHARS;/* cap to maximum */
+ safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
+ safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
+ sd->pincode_change = (time_t)RFIFOL(fd,68);
+ sd->version = RFIFOB(fd,72);
+ ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
+ // continued from char_auth_ok...
+ if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
+ (max_connect_user == 0 && sd->group_id != gm_allow_group) ||
+ ( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
+ // refuse connection (over populated)
+ WFIFOHEAD(i,3);
+ WFIFOW(i,0) = 0x6c;
+ WFIFOW(i,2) = 0;
+ WFIFOSET(i,3);
+ } else {
+ // send characters to player
+ mmo_char_send(i, sd);
+#if PACKETVER >= 20110309
+ if( pincode_enabled ){
+ // PIN code system enabled
+ if( strlen( sd->pincode ) <= 0 ){
+ // No PIN code has been set yet
+ if( pincode_force ){
+ pincode_sendstate( i, sd, PINCODE_NEW );
+ }else{
+ pincode_sendstate( i, sd, PINCODE_PASSED );
+ }
+ }else{
+ if( !pincode_changetime || ( sd->pincode_change + pincode_changetime ) > time(NULL) ){
+ struct online_char_data* node = (struct online_char_data*)idb_get( online_char_db, sd->account_id );
+
+ if( node != NULL && node->pincode_success ){
+ // User has already passed the check
+ pincode_sendstate( i, sd, PINCODE_PASSED );
+ }else{
+ // Ask user for his PIN code
+ pincode_sendstate( i, sd, PINCODE_ASK );
+ }
+ }else{
+ // User hasnt changed his PIN code too long
+ pincode_sendstate( i, sd, PINCODE_EXPIRED );
+ }
+ }
+ }else{
+ // PIN code system disabled
+ pincode_sendstate( i, sd, PINCODE_OK );
+ }
+#endif
+ }
+ }
+ RFIFOSKIP(fd,73);
+ return 1;
+}
+
+int char_parselog_keepalive(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 2)
+ return 0;
+ RFIFOSKIP(fd,2);
+ session[fd]->flag.ping = 0;
+ return 1;
+}
+
+int char_parselog_ackchangesex(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 7)
+ return 0;
+ {
+ unsigned char buf[7];
+ int i;
+
+ int acc = RFIFOL(fd,2);
+ int sex = RFIFOB(fd,6);
+ RFIFOSKIP(fd,7);
+
+ if( acc > 0 )
+ {// TODO: Is this even possible?
+ int char_id[MAX_CHARS];
+ int class_[MAX_CHARS];
+ int guild_id[MAX_CHARS];
+ int num;
+ char* data;
+
+ struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
+ if( node != NULL )
+ node->sex = sex;
+
+ // get characters
+ if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
+ Sql_ShowDebug(sql_handle);
+ for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
+ {
+ Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
+ Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
+ Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
+ }
+ num = i;
+ for( i = 0; i < num; ++i )
+ {
+ if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
+ class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
+ class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
+ class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
+ class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
+ class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
+ class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
+ {
+ // job modification
+ if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
+ class_[i] = (sex ? JOB_BARD : JOB_DANCER);
+ else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
+ class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
+ else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
+ class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
+ else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
+ class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
+ else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
+ class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
+ else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
+ class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
+ else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
+ class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
+ }
+
+ 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]) )
+ Sql_ShowDebug(sql_handle);
+
+ if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
+ inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
+ }
+ Sql_FreeResult(sql_handle);
+
+ // disconnect player if online on char-server
+ disconnect_player(acc);
+ }
+
+ // notify all mapservers about this change
+ WBUFW(buf,0) = 0x2b0d;
+ WBUFL(buf,2) = acc;
+ WBUFB(buf,6) = sex;
+ mapif_sendall(buf, 7);
+ }
+ return 1;
+}
+
+int char_parselog_ackacc2req(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+
+ { //Receive account_reg2 registry, forward to map servers.
+ unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
+ memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
+ WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
+ mapif_sendall(buf, WBUFW(buf,2));
+ RFIFOSKIP(fd, RFIFOW(fd,2));
+ }
+ return 1;
+}
+
+int char_parselog_accbannotification(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 11)
+ return 0;
+
+ { // send to all map-servers to disconnect the player
+ unsigned char buf[11];
+ WBUFW(buf,0) = 0x2b14;
+ WBUFL(buf,2) = RFIFOL(fd,2);
+ WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
+ WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
+ mapif_sendall(buf, 11);
+ }
+ // disconnect player if online on char-server
+ disconnect_player(RFIFOL(fd,2));
+ RFIFOSKIP(fd,11);
+ return 1;
+}
+
+int char_parselog_askkick(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 6)
+ return 0;
+ {
+ int aid = RFIFOL(fd,2);
+ struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid);
+ RFIFOSKIP(fd,6);
+ if( character != NULL )
+ {// account is already marked as online!
+ if( character->server > -1 )
+ { //Kick it from the map server it is on.
+ mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
+ if (character->waiting_disconnect == INVALID_TIMER)
+ character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
+ }
+ else
+ {// Manual kick from char server.
+ struct char_session_data *tsd;
+ int i;
+ ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
+ if( i < fd_max )
+ {
+ WFIFOHEAD(i,3);
+ WFIFOW(i,0) = 0x81;
+ WFIFOB(i,2) = 2; // "Someone has already logged in with this id"
+ WFIFOSET(i,3);
+ set_eof(i);
+ }
+ else // still moving to the map-server
+ set_char_offline(-1, aid);
+ }
+ }
+ idb_remove(auth_db, aid);// reject auth attempts from map-server
+ }
+ return 1;
+}
+
+int char_parselog_updip(int fd, struct char_session_data* sd){
+ if (RFIFOREST(fd) < 2)
+ return 0;
+ {
+ unsigned char buf[2];
+ uint32 new_ip = 0;
+
+ WBUFW(buf,0) = 0x2b1e;
+ mapif_sendall(buf, 2);
+
+ new_ip = host2ip(login_ip_str);
+ if (new_ip && new_ip != login_ip)
+ login_ip = new_ip; //Update login ip, too.
+
+ new_ip = host2ip(char_ip_str);
+ if (new_ip && new_ip != char_ip)
+ { //Update ip.
+ char_ip = new_ip;
+ ShowInfo("Updating IP for [%s].\n", char_ip_str);
+ // notify login server about the change
+ WFIFOHEAD(fd,6);
+ WFIFOW(fd,0) = 0x2736;
+ WFIFOL(fd,2) = htonl(char_ip);
+ WFIFOSET(fd,6);
+ }
+
+ RFIFOSKIP(fd,2);
+ }
+ return 1;
+}
+
+int parse_fromlogin(int fd) {
+ struct char_session_data* sd = NULL;
+
+ // only process data from the login-server
+ if( fd != login_fd ) {
+ ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
+ do_close(fd);
+ return 0;
+ }
+
+ if( session[fd]->flag.eof ) {
+ do_close(fd);
+ login_fd = -1;
+ loginif_on_disconnect();
+ return 0;
+ } else if ( session[fd]->flag.ping ) {/* we've reached stall time */
+ if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
+ set_eof(fd);
+ return 0;
+ } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
+ WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
+ WFIFOW(fd,0) = 0x2719;
+ WFIFOSET(fd,2);
+
+ session[fd]->flag.ping = 2;
+ }
+ }
+
+ sd = (struct char_session_data*)session[fd]->session_data;
+
+ while(RFIFOREST(fd) >= 2) {
+ uint16 command = RFIFOW(fd,0);
+
+ switch( command )
+ {
+ // acknowledgement of connect-to-loginserver request
+ case 0x2711: char_parselog_ackconnect(fd,sd); break;
+ // acknowledgement of account authentication request
+ case 0x2713: char_parselog_ackaccreq(fd, sd); break;
+ // account data
+ case 0x2717: char_parselog_reqaccdata(fd, sd); break;
+ // login-server alive packet
+ case 0x2718: char_parselog_keepalive(fd, sd); break;
+ // changesex reply
+ case 0x2723: char_parselog_ackchangesex(fd, sd); break;
+ // reply to an account_reg2 registry request
+ case 0x2729: char_parselog_ackacc2req(fd, sd); break;
+ // State change of account/ban notification (from login-server)
+ case 0x2731: char_parselog_accbannotification(fd, sd); break;
+ // Login server request to kick a character out. [Skotlex]
+ case 0x2734: char_parselog_askkick(fd,sd); break;
+ // ip address update signal from login server
+ case 0x2735: char_parselog_updip(fd,sd); break;
+ default:
+ ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
+ set_eof(fd);
+ return 0;
+ }
+ }
+
+ RFIFOFLUSH(fd);
+ return 0;
+}
+
+
+
+
+/*======================================================
+ * Login-Server help option info
+ *------------------------------------------------------*/
+void display_helpscreen(bool do_exit)
+{
+ ShowInfo("Usage: %s [options]\n", SERVER_NAME);
+ ShowInfo("\n");
+ ShowInfo("Options:\n");
+ ShowInfo(" -?, -h [--help]\t\tDisplays this help screen.\n");
+ ShowInfo(" -v [--version]\t\tDisplays the server's version.\n");
+ ShowInfo(" --run-once\t\t\tCloses server after loading (testing).\n");
+ ShowInfo(" --char-config <file>\t\tAlternative char-server configuration.\n");
+ ShowInfo(" --lan-config <file>\t\tAlternative lag configuration.\n");
+ ShowInfo(" --inter-config <file>\t\tAlternative inter-server configuration.\n");
+ ShowInfo(" --msg-config <file>\t\tAlternative message configuration.\n");
+ if( do_exit )
+ exit(EXIT_SUCCESS);
+}
+
+int char_msg_config_read(char *cfgName){
+ return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
+}
+const char* char_msg_txt(int msg_number){
+ return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
+}
+void char_do_final_msg(void){
+ _do_final_msg(CHAR_MAX_MSG,msg_table);
+}
+
+
+
void do_final(void)
{
ShowStatus("Terminating...\n");
@@ -5188,6 +5307,12 @@
ShowStatus("Finished.\n");
}
+
+void set_server_type(void)
+{
+ SERVER_TYPE = ATHENA_SERVER_CHAR;
+}
+
//------------------------------
// Function called when the server
// has received a crash signal.
@@ -5196,12 +5321,6 @@
{
}
-void set_server_type(void)
-{
- SERVER_TYPE = ATHENA_SERVER_CHAR;
-}
-
-
/// Called when a terminate signal is received.
void do_shutdown(void)
{
@@ -5317,33 +5436,4 @@
add_timer_interval(gettick()+1000, parse_console_timer, 0, 0, 1000); //start in 1s each 1sec
}
return 0;
-}
-
-int char_msg_config_read(char *cfgName){
- return _msg_config_read(cfgName,CHAR_MAX_MSG,msg_table);
-}
-const char* char_msg_txt(int msg_number){
- return _msg_txt(msg_number,CHAR_MAX_MSG,msg_table);
-}
-void char_do_final_msg(void){
- _do_final_msg(CHAR_MAX_MSG,msg_table);
-}
-
-/*======================================================
- * Login-Server help option info
- *------------------------------------------------------*/
-void display_helpscreen(bool do_exit)
-{
- ShowInfo("Usage: %s [options]\n", SERVER_NAME);
- ShowInfo("\n");
- ShowInfo("Options:\n");
- ShowInfo(" -?, -h [--help]\t\tDisplays this help screen.\n");
- ShowInfo(" -v [--version]\t\tDisplays the server's version.\n");
- ShowInfo(" --run-once\t\t\tCloses server after loading (testing).\n");
- ShowInfo(" --char-config <file>\t\tAlternative char-server configuration.\n");
- ShowInfo(" --lan-config <file>\t\tAlternative lag configuration.\n");
- ShowInfo(" --inter-config <file>\t\tAlternative inter-server configuration.\n");
- ShowInfo(" --msg-config <file>\t\tAlternative message configuration.\n");
- if( do_exit )
- exit(EXIT_SUCCESS);
-}
+}
\ No newline at end of file
Index: src/common/timer.c
===================================================================
--- src/common/timer.c (revision 17365)
+++ src/common/timer.c (working copy)
@@ -109,28 +109,28 @@
} t;
asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1]) );
-
+
return t.qw;
}
static void rdtsc_calibrate(){
uint64 t1, t2;
int32 i;
-
+
ShowStatus("Calibrating Timer Source, please wait... ");
-
+
RDTSC_CLOCK = 0;
-
+
for(i = 0; i < 5; i++){
t1 = _rdtsc();
usleep(1000000); //1000 MS
t2 = _rdtsc();
- RDTSC_CLOCK += (t2 - t1) / 1000;
+ RDTSC_CLOCK += (t2 - t1) / 1000;
}
RDTSC_CLOCK /= 5;
-
+
RDTSC_BEGINTICK = _rdtsc();
-
+
ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000) );
}
@@ -243,7 +243,7 @@
int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data)
{
int tid;
-
+
tid = acquire_timer();
timer_data[tid].tick = tick;
timer_data[tid].func = func;
@@ -267,7 +267,7 @@
ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick()));
return INVALID_TIMER;
}
-
+
tid = acquire_timer();
timer_data[tid].tick = tick;
timer_data[tid].func = func;
@@ -320,7 +320,7 @@
int settick_timer(int tid, unsigned int tick)
{
size_t i;
-
+
// search timer position
ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid);
if( i == BHEAP_LENGTH(timer_heap) )
@@ -406,6 +406,16 @@
return (unsigned long)difftime(time(NULL), start_time);
}
+//-----------------------------------------------------
+// custom timestamp formatting (from eApp)
+//-----------------------------------------------------
+const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format)
+{
+ size_t len = strftime(str, size, format, localtime(×tamp));
+ memset(str + len, '\0', size - len);
+ return str;
+}
+
void timer_init(void)
{
#if defined(ENABLE_RDTSC)
Index: src/common/timer.h
===================================================================
--- src/common/timer.h (revision 17365)
+++ src/common/timer.h (working copy)
@@ -5,6 +5,7 @@
#define _TIMER_H_
#include "../common/cbasetypes.h"
+#include <time.h>
#define DIFF_TICK(a,b) ((int)((a)-(b)))
@@ -51,6 +52,9 @@
unsigned long get_uptime(void);
+//transform a timestamp to string
+const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format);
+
int do_timer(unsigned int tick);
void timer_init(void);
void timer_final(void);
Index: src/common/mmo.h
===================================================================
--- src/common/mmo.h (revision 17365)
+++ src/common/mmo.h (working copy)
@@ -8,47 +8,9 @@
#include "../common/db.h"
#include <time.h>
-// server->client protocol version
-// 0 - pre-?
-// 1 - ? - 0x196
-// 2 - ? - 0x78, 0x79
-// 3 - ? - 0x1c8, 0x1c9, 0x1de
-// 4 - ? - 0x1d7, 0x1d8, 0x1d9, 0x1da
-// 5 - 2003-12-18aSakexe+ - 0x1ee, 0x1ef, 0x1f0, ?0x1c4, 0x1c5?
-// 6 - 2004-03-02aSakexe+ - 0x1f4, 0x1f5
-// 7 - 2005-04-11aSakexe+ - 0x229, 0x22a, 0x22b, 0x22c
-// 20061023 - 2006-10-23aSakexe+ - 0x6b, 0x6d
-// 20070521 - 2007-05-21aSakexe+ - 0x283
-// 20070821 - 2007-08-21aSakexe+ - 0x2c5
-// 20070918 - 2007-09-18aSakexe+ - 0x2d7, 0x2d9, 0x2da
-// 20071106 - 2007-11-06aSakexe+ - 0x78, 0x7c, 0x22c
-// 20080102 - 2008-01-02aSakexe+ - 0x2ec, 0x2ed , 0x2ee
-// 20081126 - 2008-11-26aSakexe+ - 0x1a2
-// 20090408 - 2009-04-08aSakexe+ - 0x44a (dont use as it overlaps with RE client packets)
-// 20080827 - 2008-08-27aRagexeRE+ - First RE Client
-// 20081217 - 2008-12-17aRagexeRE+ - 0x6d (Note: This one still use old Char Info Packet Structure)
-// 20081218 - 2008-12-17bRagexeRE+ - 0x6d (Note: From this one client use new Char Info Packet Structure)
-// 20090603 - 2009-06-03aRagexeRE+ - 0x7d7, 0x7d8, 0x7d9, 0x7da
-// 20090617 - 2009-06-17aRagexeRE+ - 0x7d9
-// 20090922 - 2009-09-22aRagexeRE+ - 0x7e5, 0x7e7, 0x7e8, 0x7e9
-// 20091103 - 2009-11-03aRagexeRE+ - 0x7f7, 0x7f8, 0x7f9
-// 20100105 - 2010-01-05aRagexeRE+ - 0x133, 0x800, 0x801
-// 20100126 - 2010-01-26aRagexeRE+ - 0x80e
-// 20100223 - 2010-02-23aRagexeRE+ - 0x80f
-// 20100413 - 2010-04-13aRagexeRE+ - 0x6b
-// 20100629 - 2010-06-29aRagexeRE+ - 0x2d0, 0xaa, 0x2d1, 0x2d2
-// 20100721 - 2010-07-21aRagexeRE+ - 0x6b, 0x6d
-// 20100727 - 2010-07-27aRagexeRE+ - 0x6b, 0x6d
-// 20100803 - 2010-08-03aRagexeRE+ - 0x6b, 0x6d, 0x827, 0x828, 0x829, 0x82a, 0x82b, 0x82c, 0x842, 0x843
-// 20101124 - 2010-11-24aRagexeRE+ - 0x856, 0x857, 0x858
-// 20110111 - 2011-01-11aRagexeRE+ - 0x6b, 0x6d
-// 20110928 - 2011-09-28aRagexeRE+ - 0x6b, 0x6d
-// 20111025 - 2011-10-25aRagexeRE+ - 0x6b, 0x6d
-// 20120307 - 2012-03-07aRagexeRE+ - 0x970
-
#ifndef PACKETVER
- #define PACKETVER 20120410
- //#define PACKETVER 20130320
+ //#define PACKETVER 20120410
+ #define PACKETVER 20130320
//#define PACKETVER 20111116
#endif
Index: src/common/utils.c
===================================================================
--- src/common/utils.c (revision 17365)
+++ src/common/utils.c (working copy)
@@ -109,16 +109,16 @@
WIN32_FIND_DATAA FindFileData;
HANDLE hFind;
char tmppath[MAX_PATH+1];
-
+
const char *path = (p ==NULL)? "." : p;
const char *pattern = (pat==NULL)? "" : pat;
-
+
checkpath(tmppath,path);
if( PATHSEP != tmppath[strlen(tmppath)-1])
strcat(tmppath, "\\*");
else
strcat(tmppath, "*");
-
+
hFind = FindFirstFileA(tmppath, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
@@ -259,6 +259,46 @@
( (uint32)(word1 << 0x10) );
}
+int date2version(int date){
+ if(date < 20040906) return 5;
+ else if(date < 20040920) return 10;
+ else if(date < 20041005) return 11;
+ else if(date < 20041025) return 12;
+ else if(date < 20041129) return 13;
+ else if(date < 20050110) return 14;
+ else if(date < 20050509) return 15;
+ else if(date < 20050628) return 16;
+ else if(date < 20050718) return 17;
+ else if(date < 20050719) return 18;
+ else if(date < 20060327) return 19;
+ else if(date < 20070108) return 20;
+ else if(date < 20070212) return 21;
+ //wtf @FIXME
+ else if(date < 20080910) return 22;
+ else if(date < 20080827) return 23;
+ else if(date < 20080910) return 24;
+ //unable to solve from date
+ else if(date < 20101124) return 25;
+ else if(date < 20111005) return 26;
+ else if(date < 20111102) return 27;
+ else if(date < 20120307) return 28;
+ else if(date < 20120410) return 29;
+ else if(date < 20120418) return 30;
+ else if(date < 20120618) return 31;
+ else if(date < 20120702) return 32;
+ else if(date < 20130320) return 33;
+ else if(date < 20130515) return 34;
+ else if(date < 20130522) return 35;
+ else if(date < 20130529) return 36;
+ else if(date < 20130605) return 37;
+ else if(date < 20130612) return 38;
+ else if(date >= 20130612) return 39;
+// else if(date < 20040920) return 40;
+// else if(date < 20040920) return 41;
+// else if(date < 20040920) return 42;
+// else if(date < 20040920) return 43;
+ else return 30; //default
+}
/// calculates the value of A / B, in percent (rounded down)
unsigned int get_percentage(const unsigned int A, const unsigned int B)
Index: src/common/utils.h
===================================================================
--- src/common/utils.h (revision 17365)
+++ src/common/utils.h (working copy)
@@ -29,4 +29,6 @@
extern uint16 MakeWord(uint8 byte0, uint8 byte1);
extern uint32 MakeDWord(uint16 word0, uint16 word1);