Index: src/login/ipban_sql.c =================================================================== --- src/login/ipban_sql.c (revision 17367) +++ src/login/ipban_sql.c (working copy) @@ -1,258 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/db.h" -#include "../common/malloc.h" -#include "../common/sql.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/timer.h" -#include "login.h" -#include "ipban.h" -#include "loginlog.h" -#include -#include - -// global sql settings -static char global_db_hostname[32] = "127.0.0.1"; -static uint16 global_db_port = 3306; -static char global_db_username[32] = "ragnarok"; -static char global_db_password[32] = "ragnarok"; -static char global_db_database[32] = "ragnarok"; -static char global_codepage[32] = ""; -// local sql settings -static char ipban_db_hostname[32] = ""; -static uint16 ipban_db_port = 0; -static char ipban_db_username[32] = ""; -static char ipban_db_password[32] = ""; -static char ipban_db_database[32] = ""; -static char ipban_codepage[32] = ""; -static char ipban_table[32] = "ipbanlist"; - -// globals -static Sql* sql_handle = NULL; -static int cleanup_timer_id = INVALID_TIMER; -static bool ipban_inited = false; - -int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data); - - -// initialize -void ipban_init(void) -{ - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - ipban_inited = true; - - if( !login_config.ipban ) - return;// ipban disabled - - if( ipban_db_hostname[0] != '\0' ) - {// local settings - username = ipban_db_username; - password = ipban_db_password; - hostname = ipban_db_hostname; - port = ipban_db_port; - database = ipban_db_database; - codepage = ipban_codepage; - } - else - {// global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - // establish connections - sql_handle = Sql_Malloc(); - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - if( login_config.ipban_cleanup_interval > 0 ) - { // set up periodic cleanup of connection history and active bans - add_timer_func_list(ipban_cleanup, "ipban_cleanup"); - cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000); - } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups - ipban_cleanup(0,0,0,0); -} - -// finalize -void ipban_final(void) -{ - if( !login_config.ipban ) - return;// ipban disabled - - if( login_config.ipban_cleanup_interval > 0 ) - // release data - delete_timer(cleanup_timer_id, ipban_cleanup); - - ipban_cleanup(0,0,0,0); // always clean up on login-server stop - - // close connections - Sql_Free(sql_handle); - sql_handle = NULL; -} - -// load configuration options -bool ipban_config_read(const char* key, const char* value) -{ - const char* signature; - - if( ipban_inited ) - return false;// settings can only be changed before init - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - signature = "ipban.sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - ipban_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(ipban_db_username, value, sizeof(ipban_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(ipban_db_password, value, sizeof(ipban_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(ipban_db_database, value, sizeof(ipban_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(ipban_codepage, value, sizeof(ipban_codepage)); - else - if( strcmpi(key, "ipban_table") == 0 ) - safestrncpy(ipban_table, value, sizeof(ipban_table)); - else - return false;// not found - return true; - } - - signature = "ipban."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "enable") == 0 ) - login_config.ipban = (bool)config_switch(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban") == 0 ) - login_config.dynamic_pass_failure_ban = (bool)config_switch(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_interval") == 0 ) - login_config.dynamic_pass_failure_ban_interval = atoi(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_limit") == 0 ) - login_config.dynamic_pass_failure_ban_limit = atoi(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_duration") == 0 ) - login_config.dynamic_pass_failure_ban_duration = atoi(value); - else - return false;// not found - return true; - } - - return false;// not found -} - -// check ip against active bans list -bool ipban_check(uint32 ip) -{ - uint8* p = (uint8*)&ip; - char* data = NULL; - int matches; - - if( !login_config.ipban ) - return false;// ipban disabled - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')", - ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]) ) - { - Sql_ShowDebug(sql_handle); - // close connection because we can't verify their connectivity. - return true; - } - - if( SQL_ERROR == Sql_NextRow(sql_handle) ) - return true;// Shouldn't happen, but just in case... - - Sql_GetData(sql_handle, 0, &data, NULL); - matches = atoi(data); - Sql_FreeResult(sql_handle); - - return( matches > 0 ); -} - -// log failed attempt -void ipban_log(uint32 ip) -{ - unsigned long failures; - - if( !login_config.ipban ) - return;// ipban disabled - - failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip. - - // if over the limit, add a temporary ban entry - if( failures >= login_config.dynamic_pass_failure_ban_limit ) - { - uint8* p = (uint8*)&ip; - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban')", - ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration) ) - Sql_ShowDebug(sql_handle); - } -} - -// remove expired bans -int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data) -{ - if( !login_config.ipban ) - return 0;// ipban disabled - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()") ) - Sql_ShowDebug(sql_handle); - - return 0; -} Index: src/login/login.c =================================================================== --- src/login/login.c (revision 17367) +++ src/login/login.c (working copy) @@ -7,16 +7,18 @@ #include "../common/md5calc.h" #include "../common/random.h" #include "../common/showmsg.h" -#include "../common/socket.h" +#include "../common/socket.h" //ip2str #include "../common/strlib.h" #include "../common/timer.h" #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" #include "loginlog.h" +#include "loginclif.h" +#include "loginchrif.h" +#include "logincnslif.h" #include #include @@ -24,11 +26,6 @@ #define LOGIN_MAX_MSG 30 static char* msg_table[LOGIN_MAX_MSG]; // Login Server messages_conf -struct Login_Config login_config; - -int login_fd; // login server socket -struct mmo_char_server server[MAX_SERVERS]; // char server data - // Account engines available static struct{ AccountDB* (*constructor)(void); @@ -53,60 +50,25 @@ // end of structure {NULL, NULL} }; -// account database -AccountDB* accounts = NULL; - -//Account registration flood protection [Kevin] -int allowed_regs = 1; -int time_allowed = 10; //in seconds - +AccountDB* accounts = NULL; // account databaseĀ« // Advanced subnet check [LuzZza] struct s_subnet { uint32 mask; uint32 char_ip; uint32 map_ip; } subnet[16]; - int subnet_count = 0; -int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip); +int login_fd; // login server socket -//----------------------------------------------------- -// Auth database -//----------------------------------------------------- -#define AUTH_TIMEOUT 30000 +AccountDB* login_get_accounts_db(void){ + return accounts; +} -struct auth_node { - - int account_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - char sex; - uint32 version; - uint8 clienttype; -}; - -static DBMap* auth_db; // int account_id -> struct auth_node* - - -//----------------------------------------------------- -// 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 int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data); - /** * @see DBCreateData */ -static DBData create_online_user(DBKey key, va_list args) +DBData create_online_user(DBKey key, va_list args) { struct online_login_data* p; CREATE(p, struct online_login_data, 1); @@ -141,7 +103,7 @@ idb_remove(online_db, account_id); } -static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data) +int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data) { struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id); if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ) @@ -154,9 +116,9 @@ } /** - * @see DBApply + * Mark a char offline */ -static int online_db_setoffline(DBKey key, DBData *data, va_list ap) +int online_db_setoffline(DBKey key, DBData *data, va_list ap) { struct online_login_data* p = db_data2ptr(data); int server = va_arg(ap, int); @@ -192,766 +154,7 @@ } -//-------------------------------------------------------------------- -// Packet send to all char-servers, except one (wos: without our self) -//-------------------------------------------------------------------- -int charif_sendallwos(int sfd, uint8* buf, size_t len) -{ - int i, c; - for( i = 0, c = 0; i < ARRAYLENGTH(server); ++i ) - { - int fd = server[i].fd; - if( session_isValid(fd) && fd != sfd ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - ++c; - } - } - - return c; -} - - -/// Initializes a server structure. -void chrif_server_init(int id) -{ - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; -} - - -/// Destroys a server structure. -void chrif_server_destroy(int id) -{ - if( server[id].fd != -1 ) - { - do_close(server[id].fd); - server[id].fd = -1; - } -} - - -/// Resets all the data related to a server. -void chrif_server_reset(int id) -{ - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. - chrif_server_destroy(id); - chrif_server_init(id); -} - - -/// Called when the connection to Char Server is disconnected. -void chrif_on_disconnect(int id) -{ - ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); - chrif_server_reset(id); -} - - -//----------------------------------------------------- -// periodic ip address synchronization -//----------------------------------------------------- -static int sync_ip_addresses(int tid, unsigned int tick, int id, intptr_t data) -{ - uint8 buf[2]; - ShowInfo("IP Sync in progress...\n"); - WBUFW(buf,0) = 0x2735; - charif_sendallwos(-1, buf, 2); - return 0; -} - - -//----------------------------------------------------- -// 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 - // password mode set to 2 -> md5(refpass, md5key) enable with - - return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || - ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); - } -} - - -//----------------------------------------------------- -// 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; -} - - -//-------------------------------------------- -// 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; -} - -//---------------------------------- -// 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; -} - -//----------------------- -// 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 \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: => Creates a new account.\n"); - } - else{ // commands with parameters - - - - } - - return 0; -} - - -//-------------------------------- -// 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); - return 0; - } - - if( session[fd]->flag.eof ){ - do_close(fd); - server[id].fd = -1; - chrif_on_disconnect(id); - return 0; - } - - ipl = server[id].ip; - ip2str(ipl, ip); - - while( RFIFOREST(fd) >= 2 ){ - uint16 command = RFIFOW(fd,0); - - 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); - } - } - break; - - case 0x2714: - if( RFIFOREST(fd) < 6 ) - return 0; - else{ - int users = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - // 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; - } - } - break; - - case 0x2715: // request from char server to change e-email from default "a@a.com" - if (RFIFOREST(fd) < 46) - return 0; - else{ - struct mmo_account acc; - char email[40]; - - int account_id = RFIFOL(fd,2); - safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email); - RFIFOSKIP(fd,46); - - 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, "a@a.com") == 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; - - 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); - } - break; - - case 0x2719: // ping request from charserver - RFIFOSKIP(fd,2); - - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2718; - WFIFOSET(fd,2); - break; - - // Map server send information to change an email of an account via char-server - case 0x2722: // 0x2722 .L .40B .40B - if (RFIFOREST(fd) < 86) - return 0; - else{ - struct mmo_account acc; - char actual_email[40]; - char new_email[40]; - - 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( 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, "a@a.com") == 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; - - 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; - - int account_id = RFIFOL(fd,2); - unsigned int state = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - 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); - - 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); - } - } - } - break; - - case 0x2725: // Receiving of map-server via char-server a ban request - if (RFIFOREST(fd) < 18) - return 0; - else{ - struct mmo_account 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); - - 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); - - acc.unban_time = timestamp; - - // Save - accounts->save(accounts, &acc); - - 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; - - case 0x2727: // Change of sex (sex is reversed) - if( RFIFOREST(fd) < 6 ) - return 0; - else{ - struct mmo_account acc; - - 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); - } - } - break; - - 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 account_id = RFIFOL(fd,4); - - 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; - - // 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)); - } - 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; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - 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; - - 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; - - case 0x272c: // Set account_id to offline [Wizputer] - if( RFIFOREST(fd) < 6 ) - return 0; - remove_online_user(RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - 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,RFIFOW(fd,2)); - } - break; - - case 0x272e: //Request account_reg2 for a character. - if (RFIFOREST(fd) < 10) - return 0; - else{ - struct mmo_account acc; - size_t off; - - 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 ) - 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; - - case 0x2738: //Change PIN Code for a account - if( RFIFOREST(fd) < 11 ) - return 0; - else{ - struct mmo_account acc; - - 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); - } - - RFIFOSKIP(fd,11); - } - break; - - case 0x2739: // PIN Code was entered wrong too often - 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; - - 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; - - default: - ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); - set_eof(fd); - return 0; - } // switch - } // while - - return 0; -} - - //------------------------------------- // Make new account //------------------------------------- @@ -964,7 +167,7 @@ //Account Registration Flood Protection by [Kevin] if( new_reg_tick == 0 ) new_reg_tick = gettick(); - if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) { + if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= login_config.allowed_regs ) { ShowNotice("Account registration denied (registration limit exceeded)\n"); return 3; } @@ -1004,7 +207,7 @@ if( DIFF_TICK(tick, new_reg_tick) > 0 ) {// Update the registration check. num_regs = 0; - new_reg_tick = tick + time_allowed*1000; + new_reg_tick = tick + login_config.time_allowed*1000; } ++num_regs; @@ -1041,8 +244,11 @@ } //Client Version check - if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ) + if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ){ + ShowNotice("Invalid version (account: '%s', auth_vers: '%d', received version: '%d', ip: %s)\n", + sd->userid, login_config.client_version_to_connect, sd->version, ip); return 5; + } len = strnlen(sd->userid, NAME_LENGTH); @@ -1093,15 +299,16 @@ if( login_config.client_hash_check && !isServer ) { struct client_hash_node *node = login_config.client_hash_nodes; + uint8 anyhash[16]; bool match = false; if( !sd->has_client_hash ) { ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); return 5; } - + memset(anyhash,1,sizeof(anyhash)); while( node ) { - if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) { + if( node->group_id <= acc.group_id && (memcmp(node->hash,anyhash,16)==0 || memcmp(node->hash, sd->client_hash, 16) == 0 ) ){ match = true; break; } @@ -1145,466 +352,97 @@ return -1; // account OK } -void login_auth_ok(struct login_session_data* sd) +//----------------------------------------------------- +// encrypted/unencrypted password check (from eApp) +//----------------------------------------------------- +bool check_encrypted(const char* str1, const char* str2, const char* passwd) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; + char tmpstr[64+1], md5str[32+1]; - uint8 server_num, n; - uint32 subnet_char_ip; - struct auth_node* node; - int i; + safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); + MD5_String(tmpstr, md5str); - if( runflag != LOGINSERVER_ST_RUNNING ) - { - // players can only login while running - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1;// server closed - WFIFOSET(fd,3); - return; - } + return (0==strcmp(passwd, md5str)); +} - if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect ) { - ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } else if( login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect ) { - ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - server_num = 0; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - if( session_isActive(server[i].fd) ) - server_num++; - - if( server_num == 0 ) - {// if no char-server, don't send void list of servers, just disconnect the player with proper message - ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - +bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass) +{ + if(passwdenc == 0) { - struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); - if( data ) - {// account is already marked as online! - if( data->char_server > -1 ) - {// Request char servers to kick this account out. [Skotlex] - uint8 buf[6]; - ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); - WBUFW(buf,0) = 0x2734; - WBUFL(buf,2) = sd->account_id; - charif_sendallwos(-1, buf, 6); - if( data->waiting_disconnect == INVALID_TIMER ) - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login - WFIFOSET(fd,3); - return; - } - else - if( data->char_server == -1 ) - {// client has authed but did not access char-server yet - // wipe previous session - idb_remove(auth_db, sd->account_id); - remove_online_user(sd->account_id); - data = NULL; - } - } + return (0==strcmp(passwd, refpass)); } - - login_log(ip, sd->userid, 100, "login ok"); - ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); - - WFIFOHEAD(fd,47+32*server_num); - WFIFOW(fd,0) = 0x69; - WFIFOW(fd,2) = 47+32*server_num; - WFIFOL(fd,4) = sd->login_id1; - WFIFOL(fd,8) = sd->account_id; - WFIFOL(fd,12) = sd->login_id2; - WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) - //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) - memset(WFIFOP(fd,20), 0, 24); - WFIFOW(fd,44) = 0; // unknown - WFIFOB(fd,46) = sex_str2num(sd->sex); - for( i = 0, n = 0; i < ARRAYLENGTH(server); ++i ) + else { - if( !session_isValid(server[i].fd) ) - continue; + // password mode set to 1 -> md5(md5key, refpass) enable with + // password mode set to 2 -> md5(refpass, md5key) enable with - subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] - WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); - WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); - WFIFOW(fd,47+n*32+26) = server[i].users; - WFIFOW(fd,47+n*32+28) = server[i].type; - WFIFOW(fd,47+n*32+30) = server[i].new_; - n++; + return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || + ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); } - WFIFOSET(fd,47+32*server_num); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->ip = ip; - node->version = sd->version; - node->clienttype = sd->clienttype; - idb_put(auth_db, sd->account_id, node); - - { - 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); - } } -/* Log the result of a failed connection attempt by sd - * result: nb (msg define in conf) - 0 = Unregistered ID - 1 = Incorrect Password - 2 = This ID is expired - 3 = Rejected from Server - 4 = You have been blocked by the GM Team - 5 = Your Game's EXE file is not the latest version - 6 = Your are Prohibited to log in until %s - 7 = Server is jammed due to over populated - 8 = No more accounts may be connected from this company - 9 = MSI_REFUSE_BAN_BY_DBA - 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED - 11 = MSI_REFUSE_BAN_BY_GM - 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK - 13 = MSI_REFUSE_SELF_LOCK - 14 = MSI_REFUSE_NOT_PERMITTED_GROUP - 15 = MSI_REFUSE_NOT_PERMITTED_GROUP - 99 = This ID has been totally erased - 100 = Login information remains at %s - 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information - 102 = This account has been temporarily prohibited from login due to a bug-related investigation - 103 = This character is being deleted. Login is temporarily unavailable for the time being - 104 = This character is being deleted. Login is temporarily unavailable for the time being - default = Unknown Error. - */ -void login_auth_failed(struct login_session_data* sd, int result) +//-------------------------------------------- +// Test to know if an IP come from LAN or WAN. +//-------------------------------------------- +int lan_subnetcheck(uint32 ip) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - if (login_config.log_login) - { - if(result >= 0 && result <= 15) - login_log(ip, sd->userid, result, msg_txt(result)); - else if(result >= 99 && result <= 104) - login_log(ip, sd->userid, result, msg_txt(result-83)); //-83 offset - else - login_log(ip, sd->userid, result, msg_txt(22)); //unknow error - } - - 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); - } - 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); - } - WFIFOSET(fd,23); -#endif + 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; } - -//---------------------------------------------------------------------------------------- -// Default packet parsing (normal players or char-server connection requests) -//---------------------------------------------------------------------------------------- -int parse_login(int fd) +//---------------------------------- +// Reading Lan Support configuration +//---------------------------------- +int login_lan_config_read(const char *lancfgName) { - struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data; - int result; + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; - 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); - return 0; + if((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; } - if( sd == NULL ) + while(fgets(line, sizeof(line), fp)) { - // 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; - } + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; - // 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 ) + if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { - - case 0x0200: // New alive packet: structure: 0x200 .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 .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 .L .24B .24B .B - case 0x0277: // S 0277 .L .24B .24B .B .16B .13B - case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B - // request client login (md5-hashed password) - case 0x01dd: // S 01dd .L .24B .16B .B - case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - case 0x027c: // S 027c .L .24B .16B .B .13B(junk) - case 0x0825: // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B - { - size_t packet_len = RFIFOREST(fd); - - if( (command == 0x0064 && packet_len < 55) - || (command == 0x0277 && packet_len < 84) - || (command == 0x02b0 && packet_len < 85) - || (command == 0x01dd && packet_len < 47) - || (command == 0x01fa && packet_len < 48) - || (command == 0x027c && packet_len < 60) - || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) ) - return 0; + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; } - { - uint32 version; - char username[NAME_LENGTH]; - char password[NAME_LENGTH]; - unsigned char passhash[16]; - uint8 clienttype; - bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); - // Shinryo: For the time being, just use token as password. - if(command == 0x0825) - { - char *accname = (char *)RFIFOP(fd, 9); - char *token = (char *)RFIFOP(fd, 0x5C); - size_t uAccLen = strlen(accname); - size_t uTokenLen = RFIFOREST(fd) - 0x5C; - - version = RFIFOL(fd,4); - - if(uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen <= 0) - { - login_auth_failed(sd, 3); - return 0; - } - - safestrncpy(username, accname, uAccLen + 1); - safestrncpy(password, token, uTokenLen + 1); - clienttype = RFIFOB(fd, 8); - } - else - { - version = RFIFOL(fd,2); - safestrncpy(username, (const char*)RFIFOP(fd,6), NAME_LENGTH); - if( israwpass ) - { - safestrncpy(password, (const char*)RFIFOP(fd,30), NAME_LENGTH); - clienttype = RFIFOB(fd,54); - } - else - { - memcpy(passhash, RFIFOP(fd,30), 16); - clienttype = RFIFOB(fd,46); - } - } - RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent - - sd->clienttype = clienttype; - sd->version = version; - safestrncpy(sd->userid, username, NAME_LENGTH); - if( israwpass ) - { - ShowStatus("Request for connection of %s (ip: %s) version=%d\n", sd->userid, ip,sd->version); - safestrncpy(sd->passwd, password, NAME_LENGTH); - if( login_config.use_md5_passwds ) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = 0; - } - else - { - ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s) version=%d\n", sd->userid, ip,sd->version); - bin2hex(sd->passwd, passhash, 16); // raw binary data here! - sd->passwdenc = PASSWORDENC; - } - - if( sd->passwdenc != 0 && login_config.use_md5_passwds ) - { - login_auth_failed(sd, 3); // send "rejected from server" - return 0; - } - - result = mmo_auth(sd, false); - - if( result == -1 ) - login_auth_ok(sd); - else - login_auth_failed(sd, result); - } - break; - - case 0x01db: // Sending request of the coding key - RFIFOSKIP(fd,2); + if( strcmpi(w1, "subnet") == 0 ) { - memset(sd->md5key, '\0', sizeof(sd->md5key)); - sd->md5keylen = (uint16)(12 + rnd() % 4); - MD5_Salt(sd->md5keylen, sd->md5key); + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); - 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)); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST(fd) < 86) - return 0; - { - 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) ) + if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) { - 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_; - - 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); + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; } - 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); - } - } - return 0; // processing will continue elsewhere - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); - set_eof(fd); - return 0; + 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; } - +/* + * Init default configuration + */ void login_set_defaults() { login_config.login_ip = INADDR_ANY; @@ -1620,7 +458,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; @@ -1630,9 +469,16 @@ login_config.use_dnsbl = false; safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); + login_config.allowed_regs = true; + login_config.time_allowed = 10; //in second login_config.client_hash_check = 0; login_config.client_hash_nodes = NULL; + + //other default conf + login_config.loginconf_name = "conf/login_athena.conf"; + login_config.lanconf_name = "conf/subnet_athena.conf"; + login_config.msgconf_name = "conf/msg_conf/login_msg.conf"; } //----------------------------------- @@ -1696,9 +542,9 @@ else if(!strcmpi(w1, "console")) login_config.console = (bool)config_switch(w2); else if(!strcmpi(w1, "allowed_regs")) //account flood protection system - allowed_regs = atoi(w2); + login_config.allowed_regs = atoi(w2); else if(!strcmpi(w1, "time_allowed")) - time_allowed = atoi(w2); + login_config.time_allowed = atoi(w2); else if(!strcmpi(w1, "use_dnsbl")) login_config.use_dnsbl = (bool)config_switch(w2); else if(!strcmpi(w1, "dnsbl_servers")) @@ -1718,15 +564,20 @@ int i; CREATE(nnode, struct client_hash_node, 1); - for (i = 0; i < 32; i += 2) { - char buf[3]; - unsigned int byte; + if(!strcmpi(md5,"any")){ + memset(nnode->hash,1,sizeof(nnode->hash)); + } + else { + for (i = 0; i < 32; i += 2) { + char buf[3]; + unsigned int byte; - memcpy(buf, &md5[i], 2); - buf[2] = 0; + memcpy(buf, &md5[i], 2); + buf[2] = 0; - sscanf(buf, "%x", &byte); - nnode->hash[i / 2] = (uint8)(byte & 0xFF); + sscanf(buf, "%x", &byte); + nnode->hash[i / 2] = (uint8)(byte & 0xFF); + } } nnode->group_id = group; @@ -1818,8 +669,7 @@ online_db->destroy(online_db, NULL); auth_db->destroy(auth_db, NULL); - for( i = 0; i < ARRAYLENGTH(server); ++i ) - chrif_server_destroy(i); + do_final_loginchrif(); if( login_fd != -1 ) { @@ -1849,12 +699,10 @@ { if( runflag != LOGINSERVER_ST_SHUTDOWN ) { - int id; runflag = LOGINSERVER_ST_SHUTDOWN; ShowStatus("Shutting down...\n"); // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - chrif_server_reset(id); + do_shutdown_loginchrif(); flush_fifos(); runflag = CORE_ST_STOP; } @@ -1874,21 +722,16 @@ // read login-server configuration login_set_defaults(); + cnsl_get_options(argc,argv); - LOGIN_CONF_NAME = "conf/login_athena.conf"; - LAN_CONF_NAME = "conf/subnet_athena.conf"; - MSG_CONF_NAME_EN = "conf/msg_conf/login_msg.conf"; + login_config_read(login_config.loginconf_name); + msg_config_read(login_config.msgconf_name); + login_lan_config_read(login_config.lanconf_name); + //end config - cli_get_options(argc,argv); - - msg_config_read(MSG_CONF_NAME_EN); - login_config_read(LOGIN_CONF_NAME); - login_lan_config_read(LAN_CONF_NAME); - rnd_init(); - for( i = 0; i < ARRAYLENGTH(server); ++i ) - chrif_server_init(i); + do_init_loginchrif(); // initialize logging if( login_config.log_login ) @@ -1911,12 +754,6 @@ add_timer_func_list(online_data_cleanup, "online_data_cleanup"); add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); - // add timer to detect ip address change and perform update - if (login_config.ip_sync_interval) { - add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); - add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); - } - // Account database init accounts = get_account_engine(); if( accounts == NULL ) { @@ -1941,14 +778,11 @@ runflag = LOGINSERVER_ST_RUNNING; } + do_init_logincnslif(); + ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); login_log(0, "login server", 100, "login server started"); - if( login_config.console ) { - add_timer_func_list(parse_console_timer, "parse_console_timer"); - add_timer_interval(gettick()+1000, parse_console_timer, 0, 0, 1000); //start in 1s each 1sec - } - return 0; } @@ -1961,21 +795,3 @@ void login_do_final_msg(void){ _do_final_msg(LOGIN_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(" --login-config \t\tAlternative login-server configuration.\n"); - ShowInfo(" --lan-config \t\tAlternative lag configuration.\n"); - ShowInfo(" --msg-config \t\tAlternative message configuration.\n"); - if( do_exit ) - exit(EXIT_SUCCESS); -} Index: src/login/account_sql.c =================================================================== --- src/login/account_sql.c (revision 17367) +++ src/login/account_sql.c (working copy) @@ -1,689 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/malloc.h" -#include "../common/mmo.h" -#include "../common/showmsg.h" -#include "../common/sql.h" -#include "../common/strlib.h" -#include "../common/timer.h" -#include "account.h" -#include -#include - -/// global defines -#define ACCOUNT_SQL_DB_VERSION 20110114 - -/// internal structure -typedef struct AccountDB_SQL -{ - AccountDB vtable; // public interface - - Sql* accounts; // SQL accounts storage - - // global sql settings - char global_db_hostname[32]; - uint16 global_db_port; - char global_db_username[32]; - char global_db_password[32]; - char global_db_database[32]; - char global_codepage[32]; - // local sql settings - char db_hostname[32]; - uint16 db_port; - char db_username[32]; - char db_password[32]; - char db_database[32]; - char codepage[32]; - // other settings - bool case_sensitive; - char account_db[32]; - char accreg_db[32]; - -} AccountDB_SQL; - -/// internal structure -typedef struct AccountDBIterator_SQL -{ - AccountDBIterator vtable; // public interface - - AccountDB_SQL* db; - int last_account_id; -} AccountDBIterator_SQL; - -/// internal functions -static bool account_db_sql_init(AccountDB* self); -static void account_db_sql_destroy(AccountDB* self); -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen); -static bool account_db_sql_set_property(AccountDB* self, const char* option, const char* value); -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc); -static bool account_db_sql_remove(AccountDB* self, const int account_id); -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc); -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id); -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid); -static AccountDBIterator* account_db_sql_iterator(AccountDB* self); -static void account_db_sql_iter_destroy(AccountDBIterator* self); -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc); - -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id); -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new); - -/// public constructor -AccountDB* account_db_sql(void) -{ - AccountDB_SQL* db = (AccountDB_SQL*)aCalloc(1, sizeof(AccountDB_SQL)); - - // set up the vtable - db->vtable.init = &account_db_sql_init; - db->vtable.destroy = &account_db_sql_destroy; - db->vtable.get_property = &account_db_sql_get_property; - db->vtable.set_property = &account_db_sql_set_property; - db->vtable.save = &account_db_sql_save; - db->vtable.create = &account_db_sql_create; - db->vtable.remove = &account_db_sql_remove; - db->vtable.load_num = &account_db_sql_load_num; - db->vtable.load_str = &account_db_sql_load_str; - db->vtable.iterator = &account_db_sql_iterator; - - // initialize to default values - db->accounts = NULL; - // global sql settings - safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname)); - db->global_db_port = 3306; - safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username)); - safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password)); - safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database)); - safestrncpy(db->global_codepage, "", sizeof(db->global_codepage)); - // local sql settings - safestrncpy(db->db_hostname, "", sizeof(db->db_hostname)); - db->db_port = 3306; - safestrncpy(db->db_username, "", sizeof(db->db_username)); - safestrncpy(db->db_password, "", sizeof(db->db_password)); - safestrncpy(db->db_database, "", sizeof(db->db_database)); - safestrncpy(db->codepage, "", sizeof(db->codepage)); - // other settings - db->case_sensitive = false; - safestrncpy(db->account_db, "login", sizeof(db->account_db)); - safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db)); - - return &db->vtable; -} - - -/* ------------------------------------------------------------------------- */ - - -/// establishes database connection -static bool account_db_sql_init(AccountDB* self) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle; - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - db->accounts = Sql_Malloc(); - sql_handle = db->accounts; - - if( db->db_hostname[0] != '\0' ) - {// local settings - username = db->db_username; - password = db->db_password; - hostname = db->db_hostname; - port = db->db_port; - database = db->db_database; - codepage = db->codepage; - } - else - {// global settings - username = db->global_db_username; - password = db->global_db_password; - hostname = db->global_db_hostname; - port = db->global_db_port; - database = db->global_db_database; - codepage = db->global_codepage; - } - - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(db->accounts); - db->accounts = NULL; - return false; - } - - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - return true; -} - -/// disconnects from database -static void account_db_sql_destroy(AccountDB* self) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - - Sql_Free(db->accounts); - db->accounts = NULL; - aFree(db); -} - -/// Gets a property from this database. -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - const char* signature; - - signature = "engine."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "name") == 0 ) - safesnprintf(buf, buflen, "sql"); - else - if( strcmpi(key, "version") == 0 ) - safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION); - else - if( strcmpi(key, "comment") == 0 ) - safesnprintf(buf, buflen, "SQL Account Database"); - else - return false;// not found - return true; - } - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_hostname); - else - if( strcmpi(key, "db_port") == 0 ) - safesnprintf(buf, buflen, "%d", db->global_db_port); - else - if( strcmpi(key, "db_username") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_username); - else - if( strcmpi(key, "db_password") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_password); - else - if( strcmpi(key, "db_database") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_database); - else - if( strcmpi(key, "codepage") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_codepage); - else - return false;// not found - return true; - } - - signature = "account.sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_hostname); - else - if( strcmpi(key, "db_port") == 0 ) - safesnprintf(buf, buflen, "%d", db->db_port); - else - if( strcmpi(key, "db_username") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_username); - else - if( strcmpi(key, "db_password") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_password); - else - if( strcmpi(key, "db_database") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_database); - else - if( strcmpi(key, "codepage") == 0 ) - safesnprintf(buf, buflen, "%s", db->codepage); - else - if( strcmpi(key, "case_sensitive") == 0 ) - safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0)); - else - if( strcmpi(key, "account_db") == 0 ) - safesnprintf(buf, buflen, "%s", db->account_db); - else - if( strcmpi(key, "accreg_db") == 0 ) - safesnprintf(buf, buflen, "%s", db->accreg_db); - else - return false;// not found - return true; - } - - return false;// not found -} - -/// if the option is supported, adjusts the internal state -static bool account_db_sql_set_property(AccountDB* self, const char* key, const char* value) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - const char* signature; - - - signature = "sql."; - if( strncmp(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - db->global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(db->global_db_username, value, sizeof(db->global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(db->global_db_password, value, sizeof(db->global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(db->global_db_database, value, sizeof(db->global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(db->global_codepage, value, sizeof(db->global_codepage)); - else - return false;// not found - return true; - } - - signature = "account.sql."; - if( strncmp(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(db->db_hostname, value, sizeof(db->db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - db->db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(db->db_username, value, sizeof(db->db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(db->db_password, value, sizeof(db->db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(db->db_database, value, sizeof(db->db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(db->codepage, value, sizeof(db->codepage)); - else - if( strcmpi(key, "case_sensitive") == 0 ) - db->case_sensitive = config_switch(value); - else - if( strcmpi(key, "account_db") == 0 ) - safestrncpy(db->account_db, value, sizeof(db->account_db)); - else - if( strcmpi(key, "accreg_db") == 0 ) - safestrncpy(db->accreg_db, value, sizeof(db->accreg_db)); - else - return false;// not found - return true; - } - - return false;// not found -} - -/// create a new account entry -/// If acc->account_id is -1, the account id will be auto-generated, -/// and its value will be written to acc->account_id if everything succeeds. -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - - // decide on the account id to assign - int account_id; - if( acc->account_id != -1 ) - {// caller specifies it manually - account_id = acc->account_id; - } - else - {// ask the database - char* data; - size_t len; - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, &len); - account_id = ( data != NULL ) ? atoi(data) : 0; - Sql_FreeResult(sql_handle); - - if( account_id < START_ACCOUNT_NUM ) - account_id = START_ACCOUNT_NUM; - - } - - // zero value is prohibited - if( account_id == 0 ) - return false; - - // absolute maximum - if( account_id > END_ACCOUNT_NUM ) - return false; - - // insert the data into the database - acc->account_id = account_id; - return mmo_auth_tosql(db, acc, true); -} - -/// delete an existing account entry + its regs -static bool account_db_sql_remove(AccountDB* self, const int account_id) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - bool result = false; - - if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") - || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id) - || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id) ) - Sql_ShowDebug(sql_handle); - else - result = true; - - result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") ); - - return result; -} - -/// update an existing account with the provided new data (both account and regs) -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - return mmo_auth_tosql(db, acc, false); -} - -/// retrieve data from db and store it in the provided data structure -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - return mmo_auth_fromsql(db, acc, account_id); -} - -/// retrieve data from db and store it in the provided data structure -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - char esc_userid[2*NAME_LENGTH+1]; - int account_id; - char* data; - - Sql_EscapeString(sql_handle, esc_userid, userid); - - // get the list of account IDs for this user ID - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'", - db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( Sql_NumRows(sql_handle) > 1 ) - {// serious problem - duplicit account - ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid); - Sql_FreeResult(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// no such entry - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); - account_id = atoi(data); - - return account_db_sql_load_num(self, acc, account_id); -} - - -/// Returns a new forward iterator. -static AccountDBIterator* account_db_sql_iterator(AccountDB* self) -{ - AccountDB_SQL* db = (AccountDB_SQL*)self; - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)aCalloc(1, sizeof(AccountDBIterator_SQL)); - - // set up the vtable - iter->vtable.destroy = &account_db_sql_iter_destroy; - iter->vtable.next = &account_db_sql_iter_next; - - // fill data - iter->db = db; - iter->last_account_id = -1; - - return &iter->vtable; -} - - -/// Destroys this iterator, releasing all allocated memory (including itself). -static void account_db_sql_iter_destroy(AccountDBIterator* self) -{ - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self; - aFree(iter); -} - - -/// Fetches the next account in the database. -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc) -{ - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self; - AccountDB_SQL* db = (AccountDB_SQL*)iter->db; - Sql* sql_handle = db->accounts; - char* data; - - // get next account ID - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1", - db->account_db, iter->last_account_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) && - SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) && - data != NULL ) - {// get account data - int account_id; - account_id = atoi(data); - if( mmo_auth_fromsql(db, acc, account_id) ) - { - iter->last_account_id = account_id; - Sql_FreeResult(sql_handle); - return true; - } - } - Sql_FreeResult(sql_handle); - return false; -} - - -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id) -{ - Sql* sql_handle = db->accounts; - char* data; - int i = 0; - - // retrieve login entry for the specified account - if( SQL_ERROR == Sql_Query(sql_handle, - "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change` FROM `%s` WHERE `account_id` = %d", - db->account_db, account_id ) - ) { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// no such entry - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); acc->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->userid, data, sizeof(acc->userid)); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass)); - Sql_GetData(sql_handle, 3, &data, NULL); acc->sex = data[0]; - Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email)); - Sql_GetData(sql_handle, 5, &data, NULL); acc->group_id = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); acc->state = strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); acc->unban_time = atol(data); - Sql_GetData(sql_handle, 8, &data, NULL); acc->expiration_time = atol(data); - Sql_GetData(sql_handle, 9, &data, NULL); acc->logincount = strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 10, &data, NULL); safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin)); - Sql_GetData(sql_handle, 11, &data, NULL); safestrncpy(acc->last_ip, data, sizeof(acc->last_ip)); - Sql_GetData(sql_handle, 12, &data, NULL); safestrncpy(acc->birthdate, data, sizeof(acc->birthdate)); - Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = atoi(data); - Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode)); - Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data); - - Sql_FreeResult(sql_handle); - - - // retrieve account regs for the specified user - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - acc->account_reg2_num = (int)Sql_NumRows(sql_handle); - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str)); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value)); - ++i; - } - Sql_FreeResult(sql_handle); - - if( i != acc->account_reg2_num ) - return false; - - return true; -} - -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new) -{ - Sql* sql_handle = db->accounts; - SqlStmt* stmt = SqlStmt_Malloc(sql_handle); - bool result = false; - int i; - - // try - do - { - - if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") ) - { - Sql_ShowDebug(sql_handle); - break; - } - - if( is_new ) - {// insert into account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, - "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - db->account_db) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - else - {// update account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - - // remove old account regs - if( SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) ) - { - Sql_ShowDebug(sql_handle); - break; - } - // insert new account regs - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id) ) - { - SqlStmt_ShowDebug(stmt); - break; - } - for( i = 0; i < acc->account_reg2_num; ++i ) - { - if( SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - if( i < acc->account_reg2_num ) - { - result = false; - break; - } - - // if we got this far, everything was successful - result = true; - - } while(0); - // finally - - result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") ); - SqlStmt_Free(stmt); - - return result; -} Index: src/login/login.h =================================================================== --- src/login/login.h (revision 17367) +++ src/login/login.h (working copy) @@ -6,6 +6,7 @@ #include "../common/mmo.h" // NAME_LENGTH,SEX_* #include "../common/core.h" // CORE_ST_LAST +#include "account.h" enum E_LOGINSERVER_ST { @@ -40,8 +41,8 @@ int fd; }; +#define MAX_SERVERS 30 struct mmo_char_server { - char name[20]; int fd; uint32 ip; @@ -49,7 +50,7 @@ uint16 users; // user count on this server uint16 type; // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P uint16 new_; // should display as 'new'? -}; +} server[MAX_SERVERS]; // char server data struct client_hash_node { int group_id; @@ -83,10 +84,15 @@ char dnsbl_servs[1024]; // comma-separated list of dnsbl servers char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) + int allowed_regs; //max number of registration + int time_allowed; //registration intervall in seconds int client_hash_check; // flags for checking client md5 struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group -}; + char *loginconf_name; + char *msgconf_name; + char *lanconf_name; +} login_config; #define sex_num2str(num) ( (num == SEX_FEMALE ) ? 'F' : (num == SEX_MALE ) ? 'M' : 'S' ) #define sex_str2num(str) ( (str == 'F' ) ? SEX_FEMALE : (str == 'M' ) ? SEX_MALE : SEX_SERVER ) @@ -94,15 +100,51 @@ #define msg_config_read(cfgName) login_msg_config_read(cfgName) #define msg_txt(msg_number) login_msg_txt(msg_number) #define do_final_msg() login_do_final_msg() - int login_msg_config_read(char *cfgName); const char* login_msg_txt(int msg_number); void login_do_final_msg(void); +//----------------------------------------------------- +// Online User Database [Wizputer] +//----------------------------------------------------- +struct online_login_data { + int account_id; + int waiting_disconnect; + int char_server; +}; +DBMap* online_db; // int account_id -> struct online_login_data* -#define MAX_SERVERS 30 -extern struct mmo_char_server server[MAX_SERVERS]; -extern struct Login_Config login_config; +//----------------------------------------------------- +// Auth database +//----------------------------------------------------- +#define AUTH_TIMEOUT 30000 +struct auth_node { + int account_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + char sex; + uint32 version; + uint8 clienttype; +}; +DBMap* auth_db; // int account_id -> struct auth_node* +AccountDB* login_get_accounts_db(void); + + +bool check_encrypted(const char* str1, const char* str2, const char* passwd); +bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass); + +int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data); +void remove_online_user(int account_id); +struct online_login_data* add_online_user(int char_server, int account_id); +int lan_subnetcheck(uint32 ip); + +int online_db_setoffline(DBKey key, DBData *data, va_list ap); +DBData create_online_user(DBKey key, va_list args); + +int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip); +int mmo_auth(struct login_session_data* sd, bool isServer); + #endif /* _LOGIN_H_ */ Index: src/login/sql/CMakeLists.txt =================================================================== --- src/login/sql/CMakeLists.txt (revision 17367) +++ src/login/sql/CMakeLists.txt (working copy) @@ -8,13 +8,19 @@ "${SQL_LOGIN_SOURCE_DIR}/account.h" "${SQL_LOGIN_SOURCE_DIR}/ipban.h" "${SQL_LOGIN_SOURCE_DIR}/login.h" + "${SQL_LOGIN_SOURCE_DIR}/loginclif.h" + "${SQL_LOGIN_SOURCE_DIR}/loginchrif.h" + "${SQL_LOGIN_SOURCE_DIR}/logincnslif.h" "${SQL_LOGIN_SOURCE_DIR}/loginlog.h" ) set( SQL_LOGIN_SOURCES - "${SQL_LOGIN_SOURCE_DIR}/account_sql.c" - "${SQL_LOGIN_SOURCE_DIR}/ipban_sql.c" + "${SQL_LOGIN_SOURCE_DIR}/account.c" + "${SQL_LOGIN_SOURCE_DIR}/ipban.c" "${SQL_LOGIN_SOURCE_DIR}/login.c" - "${SQL_LOGIN_SOURCE_DIR}/loginlog_sql.c" + "${SQL_LOGIN_SOURCE_DIR}/loginclif.c" + "${SQL_LOGIN_SOURCE_DIR}/loginchrif.c" + "${SQL_LOGIN_SOURCE_DIR}/logincnslif.c" + "${SQL_LOGIN_SOURCE_DIR}/loginlog.c" ) set( DEPENDENCIES common_sql ) set( LIBRARIES ${GLOBAL_LIBRARIES} ) Index: src/login/loginlog_sql.c =================================================================== --- src/login/loginlog_sql.c (revision 17367) +++ src/login/loginlog_sql.c (working copy) @@ -1,184 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/socket.h" -#include "../common/sql.h" -#include "../common/strlib.h" -#include -#include // exit - -// global sql settings (in ipban_sql.c) -static char global_db_hostname[32] = "127.0.0.1"; -static uint16 global_db_port = 3306; -static char global_db_username[32] = "ragnarok"; -static char global_db_password[32] = "ragnarok"; -static char global_db_database[32] = "ragnarok"; -static char global_codepage[32] = ""; -// local sql settings -static char log_db_hostname[32] = ""; -static uint16 log_db_port = 0; -static char log_db_username[32] = ""; -static char log_db_password[32] = ""; -static char log_db_database[32] = ""; -static char log_codepage[32] = ""; -static char log_login_db[256] = "loginlog"; - -static Sql* sql_handle = NULL; -static bool enabled = false; - - -// Returns the number of failed login attemps by the ip in the last minutes. -unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes) -{ - unsigned long failures = 0; - - if( !enabled ) - return 0; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE", - log_login_db, ip2str(ip,NULL), minutes) )// how many times failed account? in one ip. - Sql_ShowDebug(sql_handle); - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - Sql_GetData(sql_handle, 0, &data, NULL); - failures = strtoul(data, NULL, 10); - Sql_FreeResult(sql_handle); - } - return failures; -} - - -/*============================================= - * Records an event in the login log - *---------------------------------------------*/ -void login_log(uint32 ip, const char* username, int rcode, const char* message) -{ - char esc_username[NAME_LENGTH*2+1]; - char esc_message[255*2+1]; - int retcode; - - if( !enabled ) - return; - - Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); - - retcode = Sql_Query(sql_handle, - "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')", - log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message); - - if( retcode != SQL_SUCCESS ) - Sql_ShowDebug(sql_handle); -} - -bool loginlog_init(void) -{ - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - if( log_db_hostname[0] != '\0' ) - {// local settings - username = log_db_username; - password = log_db_password; - hostname = log_db_hostname; - port = log_db_port; - database = log_db_database; - codepage = log_codepage; - } - else - {// global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - sql_handle = Sql_Malloc(); - - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - enabled = true; - - return true; -} - -bool loginlog_final(void) -{ - Sql_Free(sql_handle); - sql_handle = NULL; - return true; -} - -bool loginlog_config_read(const char* key, const char* value) -{ - const char* signature; - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - if( strcmpi(key, "log_db_ip") == 0 ) - safestrncpy(log_db_hostname, value, sizeof(log_db_hostname)); - else - if( strcmpi(key, "log_db_port") == 0 ) - log_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "log_db_id") == 0 ) - safestrncpy(log_db_username, value, sizeof(log_db_username)); - else - if( strcmpi(key, "log_db_pw") == 0 ) - safestrncpy(log_db_password, value, sizeof(log_db_password)); - else - if( strcmpi(key, "log_db_db") == 0 ) - safestrncpy(log_db_database, value, sizeof(log_db_database)); - else - if( strcmpi(key, "log_codepage") == 0 ) - safestrncpy(log_codepage, value, sizeof(log_codepage)); - else - if( strcmpi(key, "log_login_db") == 0 ) - safestrncpy(log_login_db, value, sizeof(log_login_db)); - else - return false; - - return true; -} Index: src/login/ipban.c =================================================================== --- src/login/ipban.c (working copy) +++ src/login/ipban.c (working copy) @@ -100,7 +100,7 @@ if( login_config.ipban_cleanup_interval > 0 ) // release data delete_timer(cleanup_timer_id, ipban_cleanup); - + ipban_cleanup(0,0,0,0); // always clean up on login-server stop // close connections Index: src/login/Makefile.in =================================================================== --- src/login/Makefile.in (revision 17367) +++ src/login/Makefile.in (working copy) @@ -12,10 +12,9 @@ ../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig -LOGIN_OBJ = login.o -LOGIN_SQL_OBJ = $(LOGIN_OBJ:%=obj_sql/%) \ - obj_sql/account_sql.o obj_sql/ipban_sql.o obj_sql/loginlog_sql.o -LOGIN_H = login.h account.h ipban.h loginlog.h +LOGIN_OBJ = login.o loginclif.o loginchrif.o logincnslif.o account.o ipban.o loginlog.o +LOGIN_H = login.h loginclif.h loginchrif.h logincnslif.h account.h ipban.h loginlog.h +LOGIN_SQL_OBJ = $(LOGIN_OBJ:%=obj_sql/%) HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) @@ -62,8 +61,8 @@ login-server_sql: obj_sql $(LOGIN_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) @echo " LD $@" @@CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@ - + # login object files obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H) Index: src/map/pc.h =================================================================== --- src/map/pc.h (revision 17367) +++ src/map/pc.h (working copy) @@ -185,6 +185,7 @@ unsigned int bonus_coma : 1; } special_state; int login_id1, login_id2; + int version; unsigned short class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex] int group_id, group_pos, group_level; unsigned int permissions;/* group permissions */ Index: src/map/chrif.c =================================================================== --- src/map/chrif.c (revision 17367) +++ src/map/chrif.c (working copy) @@ -722,13 +722,14 @@ chrif_check(-1); - WFIFOHEAD(char_fd,18); + WFIFOHEAD(char_fd,19); WFIFOW(char_fd, 0) = 0x2b02; WFIFOL(char_fd, 2) = sd->bl.id; WFIFOL(char_fd, 6) = sd->login_id1; WFIFOL(char_fd,10) = sd->login_id2; WFIFOL(char_fd,14) = htonl(s_ip); - WFIFOSET(char_fd,18); + WFIFOB(char_fd,18) = sd->version; + WFIFOSET(char_fd,19); return 0; } Index: src/char/int_party.c =================================================================== --- src/char/int_party.c (revision 17367) +++ src/char/int_party.c (working copy) @@ -11,6 +11,7 @@ #include "../common/mapindex.h" #include "../common/sql.h" #include "char.h" +#include "char_mapif.h" #include "inter.h" #include "int_party.h" @@ -130,9 +131,9 @@ if( flag & PS_BREAK ) {// Break the party // we'll skip name-checking and just reset everyone with the same party id [celest] - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", schema_config.char_db, party_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", schema_config.party_db, party_id) ) Sql_ShowDebug(sql_handle); //Remove from memory idb_remove(party_db_, party_id); @@ -144,7 +145,7 @@ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " "VALUES ('%s', '%d', '%d', '%d', '%d')", - party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) + schema_config.party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -155,32 +156,32 @@ if( flag & PS_BASIC ) {// Update party info. if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", - party_db, esc_name, p->exp, p->item, party_id) ) + schema_config.party_db, esc_name, p->exp, p->item, party_id) ) Sql_ShowDebug(sql_handle); } if( flag & PS_LEADER ) {// Update leader if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", - party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) + schema_config.party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) Sql_ShowDebug(sql_handle); } - + if( flag & PS_ADDMEMBER ) {// Add one party member. if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) + schema_config.char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) Sql_ShowDebug(sql_handle); } if( flag & PS_DELMEMBER ) {// Remove one party member. if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) + schema_config.char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) Sql_ShowDebug(sql_handle); } - if( save_log ) + if( charserv_config.save_log ) ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); return 1; } @@ -201,7 +202,7 @@ #endif if( party_id <= 0 ) return NULL; - + //Load from memory p = (struct party_data*)idb_get(party_db_, party_id); if( p != NULL ) @@ -210,7 +211,7 @@ p = party_pt; memset(p, 0, sizeof(struct party_data)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", schema_config.party_db, party_id) ) { Sql_ShowDebug(sql_handle); return NULL; @@ -228,7 +229,7 @@ Sql_FreeResult(sql_handle); // Load members - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", schema_config.char_db, party_id) ) { Sql_ShowDebug(sql_handle); return NULL; @@ -247,7 +248,7 @@ } Sql_FreeResult(sql_handle); - if( save_log ) + if( charserv_config.save_log ) ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); //Add party to memory. CREATE(p, struct party_data, 1); @@ -292,7 +293,7 @@ struct party_data* p = NULL; Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", schema_config.party_db, esc_name) ) Sql_ShowDebug(sql_handle); else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { @@ -473,9 +474,9 @@ return 0; } // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + if (charserv_config.char_name_option == 1) { // only letters/symbols in char_name_letters are authorised for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { + if (strchr(charserv_config.char_name_letters, name[i]) == NULL) { if( name[i] == '"' ) { /* client-special-char */ normalize_name(name,"\""); mapif_parse_CreateParty(fd,name,item,item2,leader); @@ -484,16 +485,16 @@ mapif_party_created(fd,leader->account_id,leader->char_id,NULL); return 0; } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + } else if (charserv_config.char_name_option == 2) { // letters/symbols in char_name_letters are forbidden for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { + if (strchr(charserv_config.char_name_letters, name[i]) != NULL) { mapif_party_created(fd,leader->account_id,leader->char_id,NULL); return 0; } } p = (struct party_data*)aCalloc(1, sizeof(struct party_data)); - + memcpy(p->party.name,name,NAME_LENGTH); p->party.exp=0; p->party.item=(item?1:0)|(item2?2:0); @@ -597,7 +598,7 @@ p = inter_party_fromsql(party_id); if( p == NULL ) {// Party does not exists? - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", schema_config.char_db, party_id) ) Sql_ShowDebug(sql_handle); return 0; } @@ -634,7 +635,7 @@ int_party_check_lv(p); } } - + if (party_check_empty(p) == 0) mapif_party_info(-1, &p->party, 0); return 0; @@ -649,7 +650,7 @@ if (p == NULL) return 0; - for(i = 0; i < MAX_PARTY && + for(i = 0; i < MAX_PARTY && (p->party.member[i].account_id != account_id || p->party.member[i].char_id != char_id); i++); @@ -663,7 +664,7 @@ else p->party.count--; // Even share check situations: Family state (always breaks) - // character logging on/off is max/min level (update level range) + // character logging on/off is max/min level (update level range) // or character logging on/off has a different level (update level range using new level) if (p->family || (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || @@ -728,7 +729,7 @@ for (i = 0; i < MAX_PARTY; i++) { - if(p->party.member[i].leader) + if(p->party.member[i].leader) p->party.member[i].leader = 0; if(p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id) @@ -800,7 +801,7 @@ {// Get party_id from the database char* data; - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", schema_config.char_db, char_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -815,7 +816,7 @@ } if (party_id == 0) return 0; //No party... - + p = inter_party_fromsql(party_id); if(!p) { ShowError("Character %d's party %d not found!\n", char_id, party_id); @@ -846,7 +847,7 @@ {// Get guild_id from the database char* data; - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", schema_config.char_db, char_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -861,7 +862,7 @@ } if (party_id == 0) return 0; //No party... - + //Character has a party, set character offline and check if they were the only member online if ((p = inter_party_fromsql(party_id)) == NULL) return 0; Index: src/char/char.c =================================================================== --- src/char/char.c (revision 17367) +++ src/char/char.c (working copy) @@ -21,8 +21,12 @@ #include "int_elemental.h" #include "int_party.h" #include "int_storage.h" +#include "inter.h" +#include "char_logif.h" +#include "char_mapif.h" +#include "char_cnslif.h" +#include "char_clif.h" #include "char.h" -#include "inter.h" #include #include @@ -33,88 +37,22 @@ #include #include -#define MAX_STARTITEM 32 + #define CHAR_MAX_MSG 300 static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf -char char_db[256] = "char"; -char scdata_db[256] = "sc_data"; -char cart_db[256] = "cart_inventory"; -char inventory_db[256] = "inventory"; -char charlog_db[256] = "charlog"; -char storage_db[256] = "storage"; -char interlog_db[256] = "interlog"; -char reg_db[256] = "global_reg_value"; -char skill_db[256] = "skill"; -char memo_db[256] = "memo"; -char guild_db[256] = "guild"; -char guild_alliance_db[256] = "guild_alliance"; -char guild_castle_db[256] = "guild_castle"; -char guild_expulsion_db[256] = "guild_expulsion"; -char guild_member_db[256] = "guild_member"; -char guild_position_db[256] = "guild_position"; -char guild_skill_db[256] = "guild_skill"; -char guild_storage_db[256] = "guild_storage"; -char party_db[256] = "party"; -char pet_db[256] = "pet"; -char mail_db[256] = "mail"; // MAIL SYSTEM -char auction_db[256] = "auction"; // Auctions System -char friend_db[256] = "friends"; -char hotkey_db[256] = "hotkey"; -char quest_db[256] = "quest"; -char homunculus_db[256] = "homunculus"; -char skill_homunculus_db[256] = "skill_homunculus"; -char mercenary_db[256] = "mercenary"; -char mercenary_owner_db[256] = "mercenary_owner"; -char ragsrvinfo_db[256] = "ragsrvinfo"; +// check for exit signal +// 0 is saving complete +// other is char_id +unsigned int save_flag = 0; -// show loading/saving messages -int save_log = 1; +#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]; -static DBMap* char_db_; // int char_id -> struct mmo_charstatus* - -char db_path[1024] = "db"; - -int db_use_sqldbs; - -struct mmo_map_server { - int fd; - uint32 ip; - uint16 port; - int users; - unsigned short map[MAX_MAP_PER_SERVER]; -} server[MAX_MAP_SERVERS]; - -int login_fd=-1, char_fd=-1; -char userid[24]; -char passwd[24]; -char server_name[20]; -char wisp_server_name[NAME_LENGTH] = "Server"; -char login_ip_str[128]; -uint32 login_ip = 0; -uint16 login_port = 6900; -char char_ip_str[128]; -uint32 char_ip = 0; -char bind_ip_str[128]; -uint32 bind_ip = INADDR_ANY; -uint16 char_port = 6121; -int char_maintenance = 0; -bool char_new = true; -int char_new_display = 0; - -bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor] -int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] -char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined -#define TRIM_CHARS "\255\xA0\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] -char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor] - -int char_per_account = 0; //Maximum chars per account (default unlimited) [Sirius] -int char_del_level = 0; //From which level u can delete character [Lupus] -int char_del_delay = 86400; - -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; @@ -123,130 +61,17 @@ } subnet[16]; int subnet_count = 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: a@a.com) 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 -}; +DBMap* auth_db; // int account_id -> struct auth_node* +DBMap* online_char_db; // int account_id -> struct online_char_data* +DBMap* char_db_; // int char_id -> struct mmo_charstatus* +DBMap* char_get_authdb() { return auth_db; } +DBMap* char_get_onlinedb() { return online_char_db; } +DBMap* char_get_chardb() { return char_db_; } -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 - -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 }; - -int console = 0; - -//----------------------------------------------------- -// Auth database -//----------------------------------------------------- -#define AUTH_TIMEOUT 30000 - -struct auth_node { - int account_id; - int char_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - int sex; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - 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; - int fd; - int waiting_disconnect; - 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 int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data); -int delete_char_sql(int char_id); - /** * @see DBCreateData */ -static DBData create_online_char_data(DBKey key, va_list args) +DBData create_online_char_data(DBKey key, va_list args) { struct online_char_data* character; CREATE(character, struct online_char_data, 1); @@ -276,13 +101,7 @@ character->waiting_disconnect = INVALID_TIMER; } - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + char_send_setacconline(account_id); } @@ -292,7 +111,7 @@ struct mmo_charstatus *cp; //Update DB - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", schema_config.char_db, char_id) ) Sql_ShowDebug(sql_handle); //Check to see for online conflicts @@ -322,13 +141,7 @@ inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); //Notify login server - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + char_send_setacconline(account_id); } void set_char_offline(int char_id, int account_id) @@ -337,7 +150,7 @@ if ( char_id == -1 ) { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", schema_config.char_db, account_id) ) Sql_ShowDebug(sql_handle); } else @@ -347,7 +160,7 @@ if (cp) idb_remove(char_db_,char_id); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", schema_config.char_db, char_id) ) Sql_ShowDebug(sql_handle); } @@ -374,20 +187,15 @@ } //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. - if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272c; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); + if (char_id == -1 || character == NULL || character->fd == -1){ + char_send_setaccoffline(login_fd,account_id); } } /** * @see DBApply */ -static int char_db_setoffline(DBKey key, DBData *data, va_list ap) -{ +int char_db_setoffline(DBKey key, DBData *data, va_list ap) { struct online_char_data* character = (struct online_char_data*)db_data2ptr(data); int server = va_arg(ap, int); if (server == -1) { @@ -434,20 +242,17 @@ if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) return; - //Tell login-server to also mark all our characters as offline. - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2737; - WFIFOSET(login_fd,2); + char_send_setallaccoffline(login_fd); } void set_all_offline_sql(void) { //Set all players to 'OFFLINE' - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", schema_config.char_db) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", schema_config.guild_member_db) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", schema_config.guild_db) ) Sql_ShowDebug(sql_handle); } @@ -533,7 +338,7 @@ "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," "`delete_date`='%lu',`robe`='%d',`moves`='%d'" " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->base_level, p->job_level, + schema_config.char_db, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, p->str, p->agi, p->vit, p->int_, p->dex, p->luk, @@ -566,7 +371,7 @@ "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," "`karma`='%d',`manner`='%d', `fame`='%d'" " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->class_, + schema_config.char_db, p->class_, p->hair, p->hair_color, p->clothes_color, p->partner_id, p->father, p->mother, p->child, p->karma, p->manner, p->fame, @@ -596,7 +401,7 @@ char esc_mapname[NAME_LENGTH*2+1]; //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.memo_db, p->char_id) ) { Sql_ShowDebug(sql_handle); errors++; @@ -604,7 +409,7 @@ //insert here. StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", schema_config.memo_db); for( i = 0, count = 0; i < MAX_MEMOPOINTS; ++i ) { if( p->memo_point[i].map ) @@ -637,14 +442,14 @@ if( memcmp(p->skill, cp->skill, sizeof(p->skill)) ) { //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.skill_db, p->char_id) ) { Sql_ShowDebug(sql_handle); errors++; } StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`,`flag`) VALUES ", skill_db); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`,`flag`) VALUES ", schema_config.skill_db); //insert here. for( i = 0, count = 0; i < MAX_SKILL; ++i ) { if( p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY ) { @@ -684,14 +489,14 @@ if(diff == 1) { //Save friends - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.friend_db, char_id) ) { Sql_ShowDebug(sql_handle); errors++; } StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", schema_config.friend_db); for( i = 0, count = 0; i < MAX_FRIENDS; ++i ) { if( p->friends[i].char_id > 0 ) @@ -716,7 +521,7 @@ #ifdef HOTKEY_SAVING // hotkeys StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); + StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", schema_config.hotkey_db); diff = 0; for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){ if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) @@ -737,7 +542,7 @@ } #endif StringBuf_Destroy(&buf); - if (save_status[0]!='\0' && save_log) + if (save_status[0]!='\0' && charserv_config.save_log) ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); if (!errors) memcpy(cp, p, sizeof(struct mmo_charstatus)); @@ -759,10 +564,10 @@ int errors = 0; switch (tableswitch) { - case TABLE_INVENTORY: tablename = inventory_db; selectoption = "char_id"; break; - case TABLE_CART: tablename = cart_db; selectoption = "char_id"; break; - case TABLE_STORAGE: tablename = storage_db; selectoption = "account_id"; break; - case TABLE_GUILD_STORAGE: tablename = guild_storage_db; selectoption = "guild_id"; break; + case TABLE_INVENTORY: tablename = schema_config.inventory_db; selectoption = "char_id"; break; + case TABLE_CART: tablename = schema_config.cart_db; selectoption = "char_id"; break; + case TABLE_STORAGE: tablename = schema_config.storage_db; selectoption = "account_id"; break; + case TABLE_GUILD_STORAGE: tablename = schema_config.guild_storage_db; selectoption = "guild_id"; break; default: ShowError("Invalid table name!\n"); return 1; @@ -924,7 +729,7 @@ StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`"); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", schema_config.inventory_db, id); stmt = SqlStmt_Malloc(sql_handle); if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) @@ -980,7 +785,7 @@ // update all fields. StringBuf_Clear(&buf); StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d', `bound`='%d'", - inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound); + schema_config.inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); @@ -996,7 +801,7 @@ } } if( !found ) {// Item not present in inventory, remove it. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", inventory_db, item.id) ) { + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", schema_config.inventory_db, item.id) ) { Sql_ShowDebug(sql_handle); errors++; } @@ -1005,7 +810,7 @@ SqlStmt_Free(stmt); StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", inventory_db); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", schema_config.inventory_db); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", `card%d`", j); StringBuf_AppendStr(&buf, ") VALUES "); @@ -1074,7 +879,7 @@ "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," "`robe`,`moves`" - " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) + " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", schema_config.char_db, sd->account_id, MAX_CHARS) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) @@ -1159,7 +964,7 @@ memset(p, 0, sizeof(struct mmo_charstatus)); - if (save_log) ShowInfo("Char load request (%d)\n", char_id); + if (charserv_config.save_log) ShowInfo("Char load request (%d)\n", char_id); stmt = SqlStmt_Malloc(sql_handle); if( stmt == NULL ) @@ -1175,7 +980,7 @@ "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`" - " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) + " FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) @@ -1268,7 +1073,7 @@ //read memo data //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", schema_config.memo_db, MAX_MEMOPOINTS) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) @@ -1289,7 +1094,7 @@ StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`"); for( i = 0; i < MAX_SLOTS; ++i ) StringBuf_Printf(&buf, ", `card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.inventory_db, MAX_INVENTORY); if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) @@ -1321,7 +1126,7 @@ StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.cart_db, MAX_CART); if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) @@ -1351,7 +1156,7 @@ //read skill //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv`,`flag` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv`,`flag` FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.skill_db, MAX_SKILL) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id , 0, NULL, NULL) @@ -1373,7 +1178,7 @@ //read friends //`friends` (`char_id`, `friend_account`, `friend_id`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", schema_config.char_db, schema_config.friend_db, MAX_FRIENDS) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) @@ -1388,7 +1193,7 @@ #ifdef HOTKEY_SAVING //read hotkeys //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", schema_config.hotkey_db) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) @@ -1412,7 +1217,7 @@ strcat(t_msg, " mercenary"); - if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! + if (charserv_config.save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! SqlStmt_Free(stmt); StringBuf_Destroy(&buf); @@ -1426,7 +1231,7 @@ { char_db_= idb_alloc(DB_OPT_RELEASE_DATA); - ShowStatus("Characters per Account: '%d'.\n", char_per_account); + ShowStatus("Characters per Account: '%d'.\n", char_config.char_per_account); //the 'set offline' part is now in check_login_conn ... //if the server connects to loginserver @@ -1460,13 +1265,13 @@ Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); // check if the char exist - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", schema_config.char_db, esc_name) ) { Sql_ShowDebug(sql_handle); return 4; } - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", schema_config.char_db, esc_name, --char_dat.rename, char_id) ) { Sql_ShowDebug(sql_handle); return 3; @@ -1480,11 +1285,11 @@ memset(sd->new_name,0,sizeof(sd->new_name)); // log change - if( log_char ) + if( charserv_config.log_char ) { if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", - charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) + schema_config.charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) Sql_ShowDebug(sql_handle); } @@ -1509,29 +1314,29 @@ return -2; // control chars in name // check for reserved names - if( strcmpi(name, wisp_server_name) == 0 ) + if( strcmpi(name, charserv_config.wisp_server_name) == 0 ) return -1; // nick reserved for internal server messages // Check Authorised letters/symbols in the name of the character - if( char_name_option == 1 ) + if( charserv_config.char_name_option == 1 ) { // only letters/symbols in char_name_letters are authorised for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) + if( strchr(charserv_config.char_name_letters, name[i]) == NULL ) return -2; } - else if( char_name_option == 2 ) + else if( charserv_config.char_name_option == 2 ) { // letters/symbols in char_name_letters are forbidden for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) + if( strchr(charserv_config.char_name_letters, name[i]) != NULL ) return -2; } - if( name_ignoring_case ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name) ) { + if( charserv_config.name_ignoring_case ) { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", schema_config.char_db, esc_name) ) { Sql_ShowDebug(sql_handle); return -2; } } else { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name) ) { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", schema_config.char_db, esc_name) ) { Sql_ShowDebug(sql_handle); return -2; } @@ -1581,24 +1386,24 @@ // check the number of already existing chars in this account - if( char_per_account != 0 ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) + if( char_config.char_per_account != 0 ) { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", schema_config.char_db, sd->account_id) ) Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) >= char_per_account ) + if( Sql_NumRows(sql_handle) >= char_config.char_per_account ) return -2; // character account limit exceeded } // check char slot - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", schema_config.char_db, sd->account_id, slot) ) Sql_ShowDebug(sql_handle); if( Sql_NumRows(sql_handle) > 0 ) return -2; // slot already in use // validation success, log result - if (log_char) { + if (charserv_config.log_char) { if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) ) + schema_config.charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) ) Sql_ShowDebug(sql_handle); } #if PACKETVER >= 20120307 @@ -1606,9 +1411,9 @@ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" "'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk, + schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, 48, str, agi, vit, int_, dex, luk, (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) + mapindex_id2name(charserv_config.start_point.map), charserv_config.start_point.x, charserv_config.start_point.y, mapindex_id2name(charserv_config.start_point.map), charserv_config.start_point.x, charserv_config.start_point.y) ) { Sql_ShowDebug(sql_handle); return -2; //No, stop the procedure! @@ -1616,11 +1421,11 @@ #else //Insert the new char entry to the database if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) { Sql_ShowDebug(sql_handle); return -2; //No, stop the procedure! @@ -1630,7 +1435,7 @@ char_id = (int)Sql_LastInsertId(sql_handle); //Give the char the default items for (k = 0; k <= MAX_STARTITEM && start_items[k].nameid != 0; k ++) { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%d', '%d', '%d', '%d')", inventory_db, char_id, start_items[k].nameid, start_items[k].amount, start_items[k].pos, 1) ) + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%d', '%d', '%d', '%d')", schema_config.inventory_db, char_id, start_items[k].nameid, start_items[k].amount, start_items[k].pos, 1) ) Sql_ShowDebug(sql_handle); } @@ -1641,20 +1446,12 @@ /*----------------------------------------------------------------------------------------------------------*/ /* Divorce Players */ /*----------------------------------------------------------------------------------------------------------*/ -int divorce_char_sql(int partner_id1, int partner_id2) -{ - unsigned char buf[64]; - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2) ) +int divorce_char_sql(int partner_id1, int partner_id2){ + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", schema_config.char_db, partner_id1, partner_id2) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", schema_config.inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2) ) Sql_ShowDebug(sql_handle); - - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = partner_id1; - WBUFL(buf,6) = partner_id2; - mapif_sendall(buf,10); - + char_send_ackdivorce(partner_id1, partner_id2); return 0; } @@ -1672,7 +1469,7 @@ char *data; size_t len; - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother`,`elemental_id` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother`,`elemental_id` FROM `%s` WHERE `char_id`='%d'", schema_config.char_db, char_id)) Sql_ShowDebug(sql_handle); if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) @@ -1698,8 +1495,8 @@ //check for config char del condition [Lupus] // TODO: Move this out to packet processing (0x68/0x1fb). - if( ( char_del_level > 0 && base_level >= char_del_level ) - || ( char_del_level < 0 && base_level <= -char_del_level ) + if( ( char_config.char_del_level > 0 && base_level >= char_config.char_del_level ) + || ( char_config.char_del_level < 0 && base_level <= -char_config.char_del_level ) ) { ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); return -1; @@ -1714,9 +1511,9 @@ { // Char is Baby unsigned char buf[64]; - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", schema_config.char_db, father_id, mother_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", schema_config.skill_db, father_id, mother_id) ) Sql_ShowDebug(sql_handle); WBUFW(buf,0) = 0x2b25; @@ -1732,13 +1529,13 @@ /* delete char's pet */ //Delete the hatched pet if you have one... - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", schema_config.pet_db, char_id) ) Sql_ShowDebug(sql_handle); //Delete all pets that are stored in eggs (inventory + cart) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", schema_config.pet_db, schema_config.pet_db, schema_config.inventory_db, schema_config.inventory_db, char_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", schema_config.pet_db, schema_config.pet_db, schema_config.cart_db, schema_config.cart_db, char_id) ) Sql_ShowDebug(sql_handle); /* remove homunculus */ @@ -1753,58 +1550,58 @@ mercenary_owner_delete(char_id); /* delete char's friends list */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", schema_config.friend_db, char_id) ) Sql_ShowDebug(sql_handle); /* delete char from other's friend list */ //NOTE: Won't this cause problems for people who are already online? [Skotlex] - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", schema_config.friend_db, char_id) ) Sql_ShowDebug(sql_handle); #ifdef HOTKEY_SAVING /* delete hotkeys */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.hotkey_db, char_id) ) Sql_ShowDebug(sql_handle); #endif /* delete inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.inventory_db, char_id) ) Sql_ShowDebug(sql_handle); /* delete cart inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.cart_db, char_id) ) Sql_ShowDebug(sql_handle); /* delete memo areas */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.memo_db, char_id) ) Sql_ShowDebug(sql_handle); /* delete character registry */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", schema_config.reg_db, char_id) ) Sql_ShowDebug(sql_handle); /* delete skills */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.skill_db, char_id) ) Sql_ShowDebug(sql_handle); /* delete mails (only received) */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `dest_id`='%d'", mail_db, char_id)) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `dest_id`='%d'", schema_config.mail_db, char_id)) Sql_ShowDebug(sql_handle); #ifdef ENABLE_SC_SAVING /* status changes */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", schema_config.scdata_db, account_id, char_id) ) Sql_ShowDebug(sql_handle); #endif - if (log_char) { + if (charserv_config.log_char) { if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", - charlog_db, account_id, 0, char_id, esc_name) ) + schema_config.charlog_db, account_id, 0, char_id, esc_name) ) Sql_ShowDebug(sql_handle); } /* delete character */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", schema_config.char_db, char_id) ) Sql_ShowDebug(sql_handle); /* No need as we used inter_guild_leave [Skotlex] @@ -1813,7 +1610,7 @@ Sql_ShowDebug(sql_handle); */ - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", schema_config.guild_db, char_id) ) Sql_ShowDebug(sql_handle); else if( Sql_NumRows(sql_handle) > 0 ) mapif_parse_BreakGuild(0,guild_id); @@ -1841,7 +1638,6 @@ // Writes char data to the buffer in the format used by the client. // Used in packets 0x6b (chars info) and 0x6d (new char info) // Returns the size -#define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls) int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) { unsigned short offset = 0; @@ -1908,9 +1704,9 @@ #if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity. #if PACKETVER >= 20110928 // change slot feature (0 = disabled, otherwise enabled) - if( !char_move_enabled ) + if( (charmove_config.char_move_enabled)==0 ) WBUFL(buf,132) = 0; - else if( char_moves_unlimited ) + else if( charmove_config.char_moves_unlimited ) WBUFL(buf,132) = 1; else WBUFL(buf,132) = max( 0, (int)p->character_moves ); @@ -1925,101 +1721,9 @@ return 106+offset; } -//---------------------------------------- -// Tell client how many pages, kRO sends 17 (Yommy) -//---------------------------------------- -void char_charlist_notify( int fd, struct char_session_data* sd ){ - WFIFOHEAD(fd, 6); - WFIFOW(fd, 0) = 0x9a0; - // pages to req / send them all in 1 until mmo_chars_fromsql can split them up - WFIFOL(fd, 2) = (sd->char_slots>3)?sd->char_slots/3:1; //int TotalCnt (nb page to load) - WFIFOSET(fd,6); -} - -void char_block_character( int fd, struct char_session_data* sd ){ - WFIFOHEAD(fd, 4); - WFIFOW(fd, 0) = 0x20d; - WFIFOW(fd, 2) = 4; //packet len - WFIFOSET(fd,4); -} - -void mmo_char_send099d(int fd, struct char_session_data *sd) { - WFIFOHEAD(fd,4 + (MAX_CHARS*MAX_CHAR_BUF)); - WFIFOW(fd,0) = 0x99d; - WFIFOW(fd,2) = mmo_chars_fromsql(sd, WFIFOP(fd,4)) + 4; - WFIFOSET(fd,WFIFOW(fd,2)); -} - -//struct PACKET_CH_CHARLIST_REQ { 0x0 short PacketType} -void char_parse_req_charlist(int fd, struct char_session_data* sd){ - mmo_char_send099d(fd,sd); -} - -//---------------------------------------- -// Function to send characters to a player -//---------------------------------------- -int mmo_char_send006b(int fd, struct char_session_data* sd){ - int j, offset = 0; - //bool newvers = (sd->version >= date2version(20100413) ); -#if PACKETVER >= 20100413 - //if(newvers) //20100413 - offset += 3; -#endif - if (save_log) - ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); - - j = 24 + offset; // offset - WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6b; -#if PACKETVER >= 20100413 -// if(newvers){ //20100413 - WFIFOB(fd,4) = MAX_CHARS; // Max slots. - WFIFOB(fd,5) = sd->char_slots; // Available slots. (PremiumStartSlot) - WFIFOB(fd,6) = MAX_CHARS; // Premium slots. (Any existent chars past sd->char_slots but within MAX_CHARS will show a 'Premium Service' in red) -// } -#endif - memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes - j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); - WFIFOW(fd,2) = j; // packet len - WFIFOSET(fd,j); - - return 0; -} - -//---------------------------------------- -// Notify client about charselect window data [Ind] -//---------------------------------------- -void mmo_char_send082d(int fd, struct char_session_data* sd) { - if (save_log) - ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); - WFIFOHEAD(fd,29); - WFIFOW(fd,0) = 0x82d; - WFIFOW(fd,2) = 29; - WFIFOB(fd,4) = sd->char_slots; - WFIFOB(fd,5) = MAX_CHARS - sd->char_slots; - WFIFOB(fd,6) = MAX_CHARS - sd->char_slots; - WFIFOB(fd,7) = sd->char_slots; - WFIFOB(fd,8) = sd->char_slots; - memset(WFIFOP(fd,9), 0, 20); // unused bytes - WFIFOSET(fd,29); -} - -void mmo_char_send(int fd, struct char_session_data* sd){ - //ShowInfo("sd->version = %d\n",sd->version); -#if PACKETVER >= 20130000 - //if(sd->version > date2version(20130000) ){ - 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); -} - int char_married(int pl1, int pl2) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", schema_config.char_db, pl1) ) Sql_ShowDebug(sql_handle); else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { @@ -2038,7 +1742,7 @@ int char_child(int parent_id, int child_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", schema_config.char_db, parent_id) ) Sql_ShowDebug(sql_handle); else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { @@ -2057,7 +1761,7 @@ int char_family(int cid1, int cid2, int cid3) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", schema_config.char_db, cid1, cid2, cid3) ) Sql_ShowDebug(sql_handle); else while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { @@ -2096,8 +1800,9 @@ set_eof(i); } -static void char_auth_ok(int fd, struct char_session_data *sd) -{ + + +void char_auth_ok(int fd, struct char_session_data *sd) { struct online_char_data* character; if( (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) @@ -2107,30 +1812,18 @@ 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()+20000, chardb_waiting_disconnect, character->account_id, 0); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); + char_send_auth_result(fd,8); return; } if (character->fd >= 0 && character->fd != fd) { //There's already a connection from this account that hasn't picked a char yet. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); + char_send_auth_result(fd,8); return; } character->fd = fd; } - if (login_fd > 0) { - // request account data - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2716; - WFIFOL(login_fd,2) = sd->account_id; - WFIFOSET(login_fd,6); - } + char_send_reqaccdata(login_fd,sd); // request account data // mark session as 'authed' sd->auth = true; @@ -2141,469 +1834,6 @@ // continues when account data is received... } -int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); -void mapif_server_reset(int id); - - -/// Resets all the data. -void loginif_reset(void) -{ - int id; - // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - mapif_server_reset(id); - flush_fifos(); - exit(EXIT_FAILURE); -} - - -/// Checks the conditions for the server to stop. -/// Releases the cookie when all characters are saved. -/// If all the conditions are met, it stops the core loop. -void loginif_check_shutdown(void) -{ - if( runflag != CHARSERVER_ST_SHUTDOWN ) - return; - runflag = CORE_ST_STOP; -} - - -/// Called when the connection to Login Server is disconnected. -void loginif_on_disconnect(void) -{ - ShowWarning("Connection to Login Server lost.\n\n"); -} - - -/// Called when all the connection steps are completed. -void loginif_on_ready(void) -{ - int i; - - loginif_check_shutdown(); - - //Send online accounts to login server. - send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); - - // if no map-server already connected, display a message... - ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0] ); - if( i == ARRAYLENGTH(server) ) - 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); - -void do_init_loginif(void) -{ - // establish char-login connection if not present - add_timer_func_list(check_connect_login_server, "check_connect_login_server"); - add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); - - // send a list of all online account IDs to login server - add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); - add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour -} - -void do_final_loginif(void) -{ - if( login_fd != -1 ) - { - do_close(login_fd); - login_fd = -1; - } -} - -int request_accreg2(int account_id, int char_id) -{ - if (login_fd > 0) { - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x272e; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = char_id; - WFIFOSET(login_fd,10); - return 1; - } - return 0; -} - -//Send packet forward to login-server for account saving -int save_accreg2(unsigned char* buf, int len) -{ - if (login_fd > 0) { - WFIFOHEAD(login_fd,len+4); - memcpy(WFIFOP(login_fd,4), buf, len); - WFIFOW(login_fd,0) = 0x2728; - WFIFOW(login_fd,2) = len+4; - WFIFOSET(login_fd,len+4); - return 1; - } - return 0; -} - void char_read_fame_list(void) { int i; @@ -2615,7 +1845,7 @@ memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); // Build Blacksmith ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", schema_config.char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith) ) Sql_ShowDebug(sql_handle); for( i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) { @@ -2630,7 +1860,7 @@ memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); } // Build Alchemist ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", schema_config.char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist) ) Sql_ShowDebug(sql_handle); for( i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) { @@ -2645,7 +1875,7 @@ memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); } // Build Taekwon ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", schema_config.char_db, JOB_TAEKWON, fame_list_size_taekwon) ) Sql_ShowDebug(sql_handle); for( i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) { @@ -2662,53 +1892,7 @@ Sql_FreeResult(sql_handle); } -// Send map-servers the fame ranking lists -int char_send_fame_list(int fd) -{ - int i, len = 8; - unsigned char buf[32000]; - WBUFW(buf,0) = 0x2b1b; - - for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add blacksmith's block length - WBUFW(buf, 6) = len; - - for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add alchemist's block length - WBUFW(buf, 4) = len; - - for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add total packet length - WBUFW(buf, 2) = len; - - if (fd != -1) - mapif_send(fd, buf, len); - else - mapif_sendall(buf, len); - - return 0; -} - -void char_update_fame_list(int type, int index, int fame) -{ - unsigned char buf[8]; - WBUFW(buf,0) = 0x2b22; - WBUFB(buf,2) = type; - WBUFB(buf,3) = index; - WBUFL(buf,4) = fame; - mapif_sendall(buf, 8); -} - //Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size) //Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) int char_loadName(int char_id, char* name) @@ -2716,7 +1900,7 @@ char* data; size_t len; - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", schema_config.char_db, char_id) ) Sql_ShowDebug(sql_handle); else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { @@ -2726,7 +1910,7 @@ } else { - safestrncpy(name, unknown_char_name, NAME_LENGTH); + safestrncpy(name, charserv_config.unknown_char_name, NAME_LENGTH); } return 0; } @@ -2734,806 +1918,6 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port); -/// Initializes a server structure. -void mapif_server_init(int id) -{ - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; -} - - -/// Destroys a server structure. -void mapif_server_destroy(int id) -{ - if( server[id].fd == -1 ) - { - do_close(server[id].fd); - server[id].fd = -1; - } -} - - -/// Resets all the data related to a server. -void mapif_server_reset(int id) -{ - int i,j; - unsigned char buf[16384]; - int fd = server[id].fd; - //Notify other map servers that this one is gone. [Skotlex] - WBUFW(buf,0) = 0x2b20; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - j = 0; - for(i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[id].map[i]) - WBUFW(buf,10+(j++)*4) = server[id].map[i]; - if (j > 0) { - WBUFW(buf,2) = j * 4 + 10; - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `index`='%d'", ragsrvinfo_db, server[id].fd) ) - Sql_ShowDebug(sql_handle); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. - mapif_server_destroy(id); - mapif_server_init(id); -} - - -/// Called when the connection to a Map Server is disconnected. -void mapif_on_disconnect(int id) -{ - ShowStatus("Map-server #%d has disconnected.\n", id); - mapif_server_reset(id); -} - - -int parse_frommap(int fd) -{ - 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; - } - 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)){ - - case 0x2afa: // Receiving map names list from the map-server - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - 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++; - } - - 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); - - // 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; - - case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] - 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) ) - { - Sql_ShowDebug(sql_handle); - break; - } - 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_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); - } - } - Sql_FreeResult(sql_handle); -#endif - RFIFOSKIP(fd, 10); - } - break; - - 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; - - 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; - - 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; - } - //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x2b01: // Receive character data from map-server for saving - 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)) - { - 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); - } - RFIFOSKIP(fd,size); - } - break; - - 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( 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; - - // 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); - - //Set char to "@ char select" in online db [Kevin] - set_char_charselect(account_id); - - { - struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, account_id); - - if( character != NULL ){ - character->pincode_success = true; - } - } - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 1;// ok - WFIFOSET(fd,7); - } - } - 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; - - 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( 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); - - // 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. - - //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); - } - break; - - 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; - - case 0x2b08: // char name request - 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); - - RFIFOSKIP(fd,6); - break; - - 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 .L .40B .40B - WFIFOW(login_fd,0) = 0x2722; - WFIFOSET(login_fd,86); - } - RFIFOSKIP(fd, 86); - break; - - 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 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_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] -// 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; - } - } - - 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); - } - } - break; - - case 0x2b10: // Update and send fame ranking list - 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) - { - 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 - - 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 - {// 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); - } - - RFIFOSKIP(fd,11); - } - break; - - // Divorce chars - case 0x2b11: - if( RFIFOREST(fd) < 10 ) - return 0; - divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b16: // Receive rates [Wizputer] - if( RFIFOREST(fd) < 14 ) - return 0; - { - char esc_server_name[sizeof(server_name)*2+1]; - - 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; - - 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; - - case 0x2b18: // Reset all chars to offline [Wizputer] - set_all_offline(id); - RFIFOSKIP(fd,2); - break; - - 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; - { -#ifdef ENABLE_SC_SAVING - int count, aid, cid; - - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); - count = RFIFOW(fd, 12); - - if( count > 0 ) - { - 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); - } -#endif - RFIFOSKIP(fd, RFIFOW(fd, 2)); - } - break; - - case 0x2b23: // map-server alive packet - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2b24; - WFIFOSET(fd,2); - RFIFOSKIP(fd,2); - break; - - case 0x2b26: // auth request from map-server - 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; - - 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); - 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; - - 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); - } - } - break; - - 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; - - 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 */ - - 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 */ - } - 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); - return 0; - } - } // switch - } // while - - return 0; -} - -void do_init_mapif(void) -{ - int i; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - mapif_server_init(i); -} - -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) @@ -3555,17 +1939,10 @@ 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 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 ) { @@ -3578,937 +1955,8 @@ } -/// @param result -/// 0 (0x718): An unknown error has occurred. -/// 1: none/success -/// 3 (0x719): A database error occurred. -/// 4 (0x71a): To delete a character you must withdraw from the guild. -/// 5 (0x71b): To delete a character you must withdraw from the party. -/// Any (0x718): An unknown error has occurred. -void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) -{// HC: <0828>.W .L .L .L - WFIFOHEAD(fd,14); - WFIFOW(fd,0) = 0x828; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOL(fd,10) = TOL(delete_date); - WFIFOSET(fd,14); -} - -/// @param result -/// 0 (0x718): An unknown error has occurred. -/// 1: none/success -/// 2 (0x71c): Due to system settings can not be deleted. -/// 3 (0x719): A database error occurred. -/// 4 (0x71d): Deleting not yet possible time. -/// 5 (0x71e): Date of birth do not match. -/// Any (0x718): An unknown error has occurred. -void char_delete2_accept_ack(int fd, int char_id, uint32 result) -{// HC: <082a>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82a; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - 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. -/// Any (0x718): An unknown error has occurred. -void char_delete2_cancel_ack(int fd, int char_id, uint32 result) -{// HC: <082c>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); -} - - -static void char_delete2_req(int fd, struct char_session_data* sd) -{// CH: <0827>.W .L - int char_id, i; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - 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; - } - - 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; - } - - 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; - } - -/* - // Aegis imposes these checks probably to avoid dead member - // entries in guilds/parties, otherwise they are not required. - // TODO: Figure out how these are enforced during waiting. - if( guild_id ) - {// character in guild - char_delete2_ack(fd, char_id, 4, 0); - return; - } - - if( party_id ) - {// character in party - char_delete2_ack(fd, char_id, 5, 0); - return; - } -*/ - - // success - delete_date = time(NULL)+char_del_delay; - - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - char_delete2_ack(fd, char_id, 1, delete_date); -} - - -static void char_delete2_accept(int fd, struct char_session_data* sd) -{// CH: <0829>.W .L .6B - char birthdate[8+1]; - int char_id, i, k; - unsigned int base_level; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); - - // construct "YY-MM-DD" - birthdate[0] = RFIFOB(fd,6); - birthdate[1] = RFIFOB(fd,7); - birthdate[2] = '-'; - birthdate[3] = RFIFOB(fd,8); - birthdate[4] = RFIFOB(fd,9); - birthdate[5] = '-'; - birthdate[6] = RFIFOB(fd,10); - birthdate[7] = RFIFOB(fd,11); - birthdate[8] = 0; - - 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; - } - - 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; - } - - Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 1, &data, NULL); delete_date = strtoul(data, NULL, 10); - - if( !delete_date || delete_date>time(NULL) ) - {// not queued or delay not yet passed - char_delete2_accept_ack(fd, char_id, 4); - return; - } - - 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; - } - - 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; - } - - // success - if( delete_char_sql(char_id) < 0 ) - { - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - // refresh character list cache - for(k = i; k < MAX_CHARS-1; k++) - { - sd->found_char[k] = sd->found_char[k+1]; - } - sd->found_char[MAX_CHARS-1] = -1; - - char_delete2_accept_ack(fd, char_id, 1); -} - - -static void char_delete2_cancel(int fd, struct char_session_data* sd) -{// CH: <082b>.W .L - int char_id, i; - - char_id = RFIFOL(fd,2); - - 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; - } - - // there is no need to check, whether or not the character was - // queued for deletion, as the client prints an error message by - // itself, if it was not the case (@see char_delete2_cancel_ack) - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - char_delete2_cancel_ack(fd, char_id, 1); -} - - -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); - 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 ) - { - - // request to connect - // 0065 .L .L .L .W .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); - } - } - } - 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 .24B .B .W .W - case 0x970: - FIFOSD_CHECK(31); -#else - // S 0067 .24B .B .B .B .B .B .B .B .W .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("a@a.com", sd->email) || //it is not default email, or - (strcmp("a@a.com", 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 .l - case 0x187: - if (RFIFOREST(fd) < 6) - return 0; - RFIFOSKIP(fd,6); - break; - // char rename request - // R 08fc .l .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 .l .l .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 .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 .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 .w .l .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; - } - } - - RFIFOFLUSH(fd); - return 0; -} - -// Console Command Parser [Wizputer] -int parse_console(const char* buf) -{ - char type[64]; - char command[64]; - int n=0; - - if( ( n = sscanf(buf, "%63[^:]:%63[^\n]", 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 && 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"); - } - 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"); - } - - return 0; -} - -int mapif_sendall(unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; -} - -int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0 && fd != sfd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; -} - -int mapif_send(int fd, unsigned char *buf, unsigned int len) -{ - if (fd >= 0) { - int i; - ARR_FIND( 0, ARRAYLENGTH(server), i, fd == server[i].fd ); - if( i < ARRAYLENGTH(server) ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - return 1; - } - } - return 0; -} - -int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) -{ - uint8 buf[6]; +int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data){ int users = count_users(); // only send an update when needed @@ -4517,192 +1965,12 @@ return 0; prev_users = users; - if( login_fd > 0 && session[login_fd] ) - { - // send number of user to login server - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2714; - WFIFOL(login_fd,2) = users; - WFIFOSET(login_fd,6); - } - - // send number of players to all map-servers - WBUFW(buf,0) = 0x2b00; - WBUFL(buf,2) = users; - mapif_sendall(buf,6); - + char_send_usercount(users); + char_sendall_playercount(users); return 0; } -/** - * Load this character's account id into the 'online accounts' packet - * @see DBApply - */ -static int send_accounts_tologin_sub(DBKey key, DBData *data, va_list ap) -{ - struct online_char_data* character = db_data2ptr(data); - int* i = va_arg(ap, int*); - if(character->server > -1) - { - WFIFOL(login_fd,8+(*i)*4) = character->account_id; - (*i)++; - return 1; - } - return 0; -} - -int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data) -{ - if (login_fd > 0 && session[login_fd]) - { - // send account list to login server - int users = online_char_db->size(online_char_db); - int i = 0; - - WFIFOHEAD(login_fd,8+users*4); - WFIFOW(login_fd,0) = 0x272d; - online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); - WFIFOW(login_fd,2) = 8+ i*4; - WFIFOL(login_fd,4) = i; - WFIFOSET(login_fd,WFIFOW(login_fd,2)); - } - 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; - - 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; -} - -//------------------------------------------------ -//Pincode system -//------------------------------------------------ -void pincode_check( int fd, struct char_session_data* sd ){ - char pin[PINCODE_LENGTH+1]; - - memset(pin,0,PINCODE_LENGTH+1); - - 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 ); - } -} - -int pincode_compare( int fd, struct char_session_data* sd, char* pin ){ - if( strcmp( sd->pincode, pin ) == 0 ){ - sd->pincode_try = 0; - return 1; - }else{ - pincode_sendstate( fd, sd, PINCODE_WRONG ); - - if( pincode_maxtry && ++sd->pincode_try >= pincode_maxtry ){ - pincode_notifyLoginPinError( sd->account_id ); - } - - return 0; - } -} - -void pincode_change( int fd, struct char_session_data* sd ){ - char oldpin[PINCODE_LENGTH+1]; - char newpin[PINCODE_LENGTH+1]; - - memset(oldpin,0,PINCODE_LENGTH+1); - memset(newpin,0,PINCODE_LENGTH+1); - - 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); - pincode_decrypt(sd->pincode_seed,newpin); - - pincode_notifyLoginPinUpdate( sd->account_id, newpin ); - strncpy(sd->pincode, newpin, sizeof(newpin)); - - pincode_sendstate( fd, sd, PINCODE_PASSED ); -} - -void pincode_setnew( int fd, struct char_session_data* sd ){ - char newpin[PINCODE_LENGTH+1]; - - memset(newpin,0,PINCODE_LENGTH+1); - - strncpy( newpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH ); - pincode_decrypt( sd->pincode_seed, newpin ); - - pincode_notifyLoginPinUpdate( sd->account_id, newpin ); - strncpy( sd->pincode, newpin, strlen( newpin ) ); - - pincode_sendstate( fd, sd, PINCODE_PASSED ); -} - -// 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); -} - -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_decrypt( uint32 userSeed, char* pin ){ int i, pos; char tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; @@ -4728,74 +1996,27 @@ 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; - } +int pincode_compare( int fd, struct char_session_data* sd, char* pin ){ + if( strcmp( sd->pincode, pin ) == 0 ){ + sd->pincode_try = 0; + return 1; + }else{ + pincode_sendstate( fd, sd, PINCODE_WRONG ); - // We dont even have a character on the chosen slot? - if( sd->found_char[from] <= 0 ){ - moveCharSlotReply( fd, sd, from, 1 ); - return; - } - - if( sd->found_char[to] > 0 ){ - // We want to move to a used position - if( char_movetoused ){ // TODO: check if the target is in deletion process - // Admin is friendly and uses triangle exchange - if( SQL_ERROR == Sql_QueryStr(sql_handle, "START TRANSACTION") - || SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id` = '%d'", char_db, to, sd->found_char[from] ) - || SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id` = '%d'", char_db, from, sd->found_char[to] ) - || SQL_ERROR == Sql_QueryStr(sql_handle, "COMMIT") - ){ - moveCharSlotReply( fd, sd, from, 1 ); - Sql_ShowDebug(sql_handle); - Sql_QueryStr(sql_handle,"ROLLBACK"); - return; - } - }else{ - // Admin doesnt allow us to - moveCharSlotReply( fd, sd, from, 1 ); - return; + if( pincode_config.pincode_maxtry && ++sd->pincode_try >= pincode_config.pincode_maxtry ){ + pincode_notifyLoginPinError( sd->account_id ); } - }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; - } - if( !char_moves_unlimited ){ - sd->char_moves[from]--; - Sql_Query(sql_handle, "UPDATE `%s` SET `moves`='%d' WHERE `char_id`='%d'", char_db, sd->char_moves[from], sd->found_char[from] ); + return 0; } - - // We successfully moved the char - time to notify the client - moveCharSlotReply( fd, sd, from, 0 ); - mmo_char_send(fd, sd); } -// 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] //------------------------------------------------ -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data) +int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data) { struct online_char_data* character; if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) @@ -4828,6 +2049,8 @@ return 0; } + + //---------------------------------- // Reading Lan Support configuration // Rewrote: Anvanced subnet check [LuzZza] @@ -4901,63 +2124,63 @@ continue; if(!strcmpi(w1,"char_db")) - safestrncpy(char_db, w2, sizeof(char_db)); + safestrncpy(schema_config.char_db, w2, sizeof(schema_config.char_db)); else if(!strcmpi(w1,"scdata_db")) - safestrncpy(scdata_db, w2, sizeof(scdata_db)); + safestrncpy(schema_config.scdata_db, w2, sizeof(schema_config.scdata_db)); else if(!strcmpi(w1,"cart_db")) - safestrncpy(cart_db, w2, sizeof(cart_db)); + safestrncpy(schema_config.cart_db, w2, sizeof(schema_config.cart_db)); else if(!strcmpi(w1,"inventory_db")) - safestrncpy(inventory_db, w2, sizeof(inventory_db)); + safestrncpy(schema_config.inventory_db, w2, sizeof(schema_config.inventory_db)); else if(!strcmpi(w1,"charlog_db")) - safestrncpy(charlog_db, w2, sizeof(charlog_db)); + safestrncpy(schema_config.charlog_db, w2, sizeof(schema_config.charlog_db)); else if(!strcmpi(w1,"storage_db")) - safestrncpy(storage_db, w2, sizeof(storage_db)); + safestrncpy(schema_config.storage_db, w2, sizeof(schema_config.storage_db)); else if(!strcmpi(w1,"reg_db")) - safestrncpy(reg_db, w2, sizeof(reg_db)); + safestrncpy(schema_config.reg_db, w2, sizeof(schema_config.reg_db)); else if(!strcmpi(w1,"skill_db")) - safestrncpy(skill_db, w2, sizeof(skill_db)); + safestrncpy(schema_config.skill_db, w2, sizeof(schema_config.skill_db)); else if(!strcmpi(w1,"interlog_db")) - safestrncpy(interlog_db, w2, sizeof(interlog_db)); + safestrncpy(schema_config.interlog_db, w2, sizeof(schema_config.interlog_db)); else if(!strcmpi(w1,"memo_db")) - safestrncpy(memo_db, w2, sizeof(memo_db)); + safestrncpy(schema_config.memo_db, w2, sizeof(schema_config.memo_db)); else if(!strcmpi(w1,"guild_db")) - safestrncpy(guild_db, w2, sizeof(guild_db)); + safestrncpy(schema_config.guild_db, w2, sizeof(schema_config.guild_db)); else if(!strcmpi(w1,"guild_alliance_db")) - safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); + safestrncpy(schema_config.guild_alliance_db, w2, sizeof(schema_config.guild_alliance_db)); else if(!strcmpi(w1,"guild_castle_db")) - safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); + safestrncpy(schema_config.guild_castle_db, w2, sizeof(schema_config.guild_castle_db)); else if(!strcmpi(w1,"guild_expulsion_db")) - safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); + safestrncpy(schema_config.guild_expulsion_db, w2, sizeof(schema_config.guild_expulsion_db)); else if(!strcmpi(w1,"guild_member_db")) - safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); + safestrncpy(schema_config.guild_member_db, w2, sizeof(schema_config.guild_member_db)); else if(!strcmpi(w1,"guild_skill_db")) - safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); + safestrncpy(schema_config.guild_skill_db, w2, sizeof(schema_config.guild_skill_db)); else if(!strcmpi(w1,"guild_position_db")) - safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); + safestrncpy(schema_config.guild_position_db, w2, sizeof(schema_config.guild_position_db)); else if(!strcmpi(w1,"guild_storage_db")) - safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); + safestrncpy(schema_config.guild_storage_db, w2, sizeof(schema_config.guild_storage_db)); else if(!strcmpi(w1,"party_db")) - safestrncpy(party_db, w2, sizeof(party_db)); + safestrncpy(schema_config.party_db, w2, sizeof(schema_config.party_db)); else if(!strcmpi(w1,"pet_db")) - safestrncpy(pet_db, w2, sizeof(pet_db)); + safestrncpy(schema_config.pet_db, w2, sizeof(schema_config.pet_db)); else if(!strcmpi(w1,"mail_db")) - safestrncpy(mail_db, w2, sizeof(mail_db)); + safestrncpy(schema_config.mail_db, w2, sizeof(schema_config.mail_db)); else if(!strcmpi(w1,"auction_db")) - safestrncpy(auction_db, w2, sizeof(auction_db)); + safestrncpy(schema_config.auction_db, w2, sizeof(schema_config.auction_db)); else if(!strcmpi(w1,"friend_db")) - safestrncpy(friend_db, w2, sizeof(friend_db)); + safestrncpy(schema_config.friend_db, w2, sizeof(schema_config.friend_db)); else if(!strcmpi(w1,"hotkey_db")) - safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); + safestrncpy(schema_config.hotkey_db, w2, sizeof(schema_config.hotkey_db)); else if(!strcmpi(w1,"quest_db")) - safestrncpy(quest_db,w2,sizeof(quest_db)); + safestrncpy(schema_config.quest_db,w2,sizeof(schema_config.quest_db)); else if(!strcmpi(w1,"homunculus_db")) - safestrncpy(homunculus_db,w2,sizeof(homunculus_db)); + safestrncpy(schema_config.homunculus_db,w2,sizeof(schema_config.homunculus_db)); else if(!strcmpi(w1,"skill_homunculus_db")) - safestrncpy(skill_homunculus_db,w2,sizeof(skill_homunculus_db)); + safestrncpy(schema_config.skill_homunculus_db,w2,sizeof(schema_config.skill_homunculus_db)); else if(!strcmpi(w1,"mercenary_db")) - safestrncpy(mercenary_db,w2,sizeof(mercenary_db)); + safestrncpy(schema_config.mercenary_db,w2,sizeof(schema_config.mercenary_db)); else if(!strcmpi(w1,"mercenary_owner_db")) - safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db)); + safestrncpy(schema_config.mercenary_owner_db,w2,sizeof(schema_config.mercenary_owner_db)); //support the import command, just like any other config else if(!strcmpi(w1,"import")) sql_config_read(w2); @@ -4966,6 +2189,93 @@ ShowInfo("Done reading %s.\n", cfgName); } + +void char_set_default_sql(){ +// schema_config.db_use_sqldbs; + safestrncpy(schema_config.db_path,"db",sizeof(schema_config.db_path)); + safestrncpy(schema_config.char_db,"char",sizeof(schema_config.char_db)); + safestrncpy(schema_config.scdata_db,"sc_data",sizeof(schema_config.scdata_db)); + safestrncpy(schema_config.cart_db,"cart_inventory",sizeof(schema_config.cart_db)); + safestrncpy(schema_config.inventory_db,"inventory",sizeof(schema_config.inventory_db)); + safestrncpy(schema_config.charlog_db,"charlog",sizeof(schema_config.charlog_db)); + safestrncpy(schema_config.storage_db,"storage",sizeof(schema_config.storage_db)); + safestrncpy(schema_config.interlog_db,"interlog",sizeof(schema_config.interlog_db)); + safestrncpy(schema_config.reg_db,"global_reg_value",sizeof(schema_config.reg_db)); + safestrncpy(schema_config.skill_db,"skill",sizeof(schema_config.skill_db)); + safestrncpy(schema_config.memo_db,"memo",sizeof(schema_config.memo_db)); + safestrncpy(schema_config.guild_db,"guild",sizeof(schema_config.guild_db)); + safestrncpy(schema_config.guild_alliance_db,"guild_alliance",sizeof(schema_config.guild_alliance_db)); + safestrncpy(schema_config.guild_castle_db,"guild_castle",sizeof(schema_config.guild_castle_db)); + safestrncpy(schema_config.guild_expulsion_db,"guild_expulsion",sizeof(schema_config.guild_expulsion_db)); + safestrncpy(schema_config.guild_member_db,"guild_member",sizeof(schema_config.guild_member_db)); + safestrncpy(schema_config.guild_position_db,"guild_position",sizeof(schema_config.guild_position_db)); + safestrncpy(schema_config.guild_skill_db,"guild_skill",sizeof(schema_config.guild_skill_db)); + safestrncpy(schema_config.guild_storage_db,"guild_storage",sizeof(schema_config.guild_storage_db)); + safestrncpy(schema_config.party_db,"party",sizeof(schema_config.party_db)); + safestrncpy(schema_config.pet_db,"pet",sizeof(schema_config.pet_db)); + safestrncpy(schema_config.mail_db,"mail",sizeof(schema_config.mail_db)); // MAIL SYSTEM + safestrncpy(schema_config.auction_db,"auction",sizeof(schema_config.auction_db)); // Auctions System + safestrncpy(schema_config.friend_db,"friends",sizeof(schema_config.friend_db)); + safestrncpy(schema_config.hotkey_db,"hotkey",sizeof(schema_config.hotkey_db)); + safestrncpy(schema_config.quest_db,"quest",sizeof(schema_config.quest_db)); + safestrncpy(schema_config.homunculus_db,"homunculus",sizeof(schema_config.homunculus_db)); + safestrncpy(schema_config.skill_homunculus_db,"skill_homunculus",sizeof(schema_config.skill_homunculus_db)); + safestrncpy(schema_config.mercenary_db,"mercenary",sizeof(schema_config.mercenary_db)); + safestrncpy(schema_config.mercenary_owner_db,"mercenary_owner",sizeof(schema_config.mercenary_owner_db)); + safestrncpy(schema_config.ragsrvinfo_db,"ragsrvinfo",sizeof(schema_config.ragsrvinfo_db)); +} + +//set default config +void char_set_defaults(){ + pincode_config.pincode_enabled = true; + pincode_config.pincode_changetime = 0; + pincode_config.pincode_maxtry = 3; + pincode_config.pincode_force = true; + + charmove_config.char_move_enabled = true; + charmove_config.char_movetoused = true; + charmove_config.char_moves_unlimited = false; + + char_config.char_per_account = 0; //Maximum chars per account (default unlimited) [Sirius] + char_config.char_del_level = 0; //From which level u can delete character [Lupus] + char_config.char_del_delay = 86400; + +// charserv_config.userid[24]; +// charserv_config.passwd[24]; +// charserv_config.server_name[20]; + safestrncpy(charserv_config.wisp_server_name,"Server",sizeof(charserv_config.wisp_server_name)); +// charserv_config.login_ip_str[128]; + charserv_config.login_ip = 0; + charserv_config.login_port = 6900; +// charserv_config.char_ip_str[128]; + charserv_config.char_ip = 0; +// charserv_config.bind_ip_str[128]; + charserv_config.bind_ip = INADDR_ANY; + charserv_config.char_port = 6121; + charserv_config.char_maintenance = 0; + charserv_config.char_new = true; + charserv_config.char_new_display = 0; + + charserv_config.name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor] + charserv_config.char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] + safestrncpy(charserv_config.unknown_char_name,"Unknown",sizeof(charserv_config.unknown_char_name)); // Name to use when the requested name cannot be determined + safestrncpy(charserv_config.char_name_letters,"",sizeof(charserv_config.char_name_letters)); // list of letters/symbols allowed (or not) in a character name. by [Yor] + + charserv_config.save_log = 1; // show loading/saving messages + charserv_config.log_char = 1; // loggin char or not [devil] + charserv_config.log_inter = 1; // loggin inter or not [devil] + + charserv_config.start_point.map = mapindex_name2id("new_zone01"); //mapindex_name2id(MAP_DEFAULT); + charserv_config.start_point.x = 53; //MAP_DEFAULT_X + charserv_config.start_point.y = 111; //MAP_DEFAULT_Y + charserv_config.console = 0; + charserv_config.max_connect_user = -1; + charserv_config.gm_allow_group = -1; + charserv_config.autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + charserv_config.start_zeny = 0; + charserv_config.guild_exp_rate = 100; +} + int char_config_read(const char* cfgName) { char line[1024], w1[1024], w2[1024]; @@ -4994,72 +2304,72 @@ } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ stdout_with_ansisequence = config_switch(w2); } else if (strcmpi(w1, "userid") == 0) { - safestrncpy(userid, w2, sizeof(userid)); + safestrncpy(charserv_config.userid, w2, sizeof(charserv_config.userid)); } else if (strcmpi(w1, "passwd") == 0) { - safestrncpy(passwd, w2, sizeof(passwd)); + safestrncpy(charserv_config.passwd, w2, sizeof(charserv_config.passwd)); } else if (strcmpi(w1, "server_name") == 0) { - safestrncpy(server_name, w2, sizeof(server_name)); + safestrncpy(charserv_config.server_name, w2, sizeof(charserv_config.server_name)); } else if (strcmpi(w1, "wisp_server_name") == 0) { if (strlen(w2) >= 4) { - safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); + safestrncpy(charserv_config.wisp_server_name, w2, sizeof(charserv_config.wisp_server_name)); } } else if (strcmpi(w1, "login_ip") == 0) { - login_ip = host2ip(w2); - if (login_ip) { + charserv_config.login_ip = host2ip(w2); + if (charserv_config.login_ip) { char ip_str[16]; - safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); - ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); + safestrncpy(charserv_config.login_ip_str, w2, sizeof(charserv_config.login_ip_str)); + ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(charserv_config.login_ip, ip_str)); } } else if (strcmpi(w1, "login_port") == 0) { - login_port = atoi(w2); + charserv_config.login_port = atoi(w2); } else if (strcmpi(w1, "char_ip") == 0) { - char_ip = host2ip(w2); - if (char_ip) { + charserv_config.char_ip = host2ip(w2); + if (charserv_config.char_ip) { char ip_str[16]; - safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); - ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); + safestrncpy(charserv_config.char_ip_str, w2, sizeof(charserv_config.char_ip_str)); + ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(charserv_config.char_ip, ip_str)); } } else if (strcmpi(w1, "bind_ip") == 0) { - bind_ip = host2ip(w2); - if (bind_ip) { + charserv_config.bind_ip = host2ip(w2); + if (charserv_config.bind_ip) { char ip_str[16]; - safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); - ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); + safestrncpy(charserv_config.bind_ip_str, w2, sizeof(charserv_config.bind_ip_str)); + ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(charserv_config.bind_ip, ip_str)); } } else if (strcmpi(w1, "char_port") == 0) { - char_port = atoi(w2); + charserv_config.char_port = atoi(w2); } else if (strcmpi(w1, "char_maintenance") == 0) { - char_maintenance = atoi(w2); + charserv_config.char_maintenance = atoi(w2); } else if (strcmpi(w1, "char_new") == 0) { - char_new = (bool)atoi(w2); + charserv_config.char_new = (bool)atoi(w2); } else if (strcmpi(w1, "char_new_display") == 0) { - char_new_display = atoi(w2); + charserv_config.char_new_display = atoi(w2); } else if (strcmpi(w1, "max_connect_user") == 0) { - max_connect_user = atoi(w2); - if (max_connect_user < -1) - max_connect_user = -1; + charserv_config.max_connect_user = atoi(w2); + if (charserv_config.max_connect_user < -1) + charserv_config.max_connect_user = -1; } else if(strcmpi(w1, "gm_allow_group") == 0) { - gm_allow_group = atoi(w2); + charserv_config.gm_allow_group = atoi(w2); } else if (strcmpi(w1, "autosave_time") == 0) { - autosave_interval = atoi(w2)*1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + charserv_config.autosave_interval = atoi(w2)*1000; + if (charserv_config.autosave_interval <= 0) + charserv_config.autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; } else if (strcmpi(w1, "save_log") == 0) { - save_log = config_switch(w2); + charserv_config.save_log = config_switch(w2); } else if (strcmpi(w1, "start_point") == 0) { char map[MAP_NAME_LENGTH_EXT]; int x, y; if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) continue; - start_point.map = mapindex_name2id(map); - if (!start_point.map) + charserv_config.start_point.map = mapindex_name2id(map); + if (!charserv_config.start_point.map) ShowError("Specified start_point %s not found in map-index cache.\n", map); - start_point.x = x; - start_point.y = y; + charserv_config.start_point.x = x; + charserv_config.start_point.y = y; } else if (strcmpi(w1, "start_zeny") == 0) { - start_zeny = atoi(w2); - if (start_zeny < 0) - start_zeny = 0; + charserv_config.start_zeny = atoi(w2); + if (charserv_config.start_zeny < 0) + charserv_config.start_zeny = 0; } else if (strcmpi(w1, "start_items") == 0) { int i=0, n=0; char *lineitem, **fields; @@ -5086,31 +2396,31 @@ } aFree(fields); } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] - log_char = atoi(w2); + charserv_config.log_char = atoi(w2); } else if (strcmpi(w1, "unknown_char_name") == 0) { - safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); - unknown_char_name[NAME_LENGTH-1] = '\0'; + safestrncpy(charserv_config.unknown_char_name, w2, sizeof(charserv_config.unknown_char_name)); + charserv_config.unknown_char_name[NAME_LENGTH-1] = '\0'; } else if (strcmpi(w1, "name_ignoring_case") == 0) { - name_ignoring_case = (bool)config_switch(w2); + charserv_config.name_ignoring_case = (bool)config_switch(w2); } else if (strcmpi(w1, "char_name_option") == 0) { - char_name_option = atoi(w2); + charserv_config.char_name_option = atoi(w2); } else if (strcmpi(w1, "char_name_letters") == 0) { - safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); + safestrncpy(charserv_config.char_name_letters, w2, sizeof(charserv_config.char_name_letters)); } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] - char_per_account = atoi(w2); - if( char_per_account == 0 || char_per_account > MAX_CHARS ) { - if( char_per_account > MAX_CHARS ) - ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS); - char_per_account = MAX_CHARS; + char_config.char_per_account = atoi(w2); + if( char_config.char_per_account == 0 || char_config.char_per_account > MAX_CHARS ) { + if( char_config.char_per_account > MAX_CHARS ) + ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_config.char_per_account, MAX_CHARS); + char_config.char_per_account = MAX_CHARS; } } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] - char_del_level = atoi(w2); + char_config.char_del_level = atoi(w2); } else if (strcmpi(w1, "char_del_delay") == 0) { - char_del_delay = atoi(w2); + char_config.char_del_delay = atoi(w2); } else if(strcmpi(w1,"db_path")==0) { - safestrncpy(db_path, w2, sizeof(db_path)); + safestrncpy(schema_config.db_path, w2, sizeof(schema_config.db_path)); } else if (strcmpi(w1, "console") == 0) { - console = config_switch(w2); + charserv_config.console = config_switch(w2); } else if (strcmpi(w1, "fame_list_alchemist") == 0) { fame_list_size_chemist = atoi(w2); if (fame_list_size_chemist > MAX_FAME_LIST) { @@ -5130,27 +2440,27 @@ fame_list_size_taekwon = MAX_FAME_LIST; } } else if (strcmpi(w1, "guild_exp_rate") == 0) { - guild_exp_rate = atoi(w2); + charserv_config.guild_exp_rate = atoi(w2); } else if (strcmpi(w1, "pincode_enabled") == 0) { - pincode_enabled = config_switch(w2); + pincode_config.pincode_enabled = config_switch(w2); #if PACKETVER < 20110309 - if( pincode_enabled ) { + if( pincode_config.pincode_enabled ) { ShowWarning("pincode_enabled requires PACKETVER 20110309 or higher. Disabling...\n"); - pincode_enabled = false; + pincode_config.pincode_enabled = false; } #endif } else if (strcmpi(w1, "pincode_changetime") == 0) { - pincode_changetime = atoi(w2)*60*60*24; + pincode_config.pincode_changetime = atoi(w2)*60*60*24; } else if (strcmpi(w1, "pincode_maxtry") == 0) { - pincode_maxtry = atoi(w2); + pincode_config.pincode_maxtry = atoi(w2); } else if (strcmpi(w1, "pincode_force") == 0) { - pincode_force = config_switch(w2); + pincode_config.pincode_force = config_switch(w2); } else if (strcmpi(w1, "char_move_enabled") == 0) { - char_move_enabled = config_switch(w2); + charmove_config.char_move_enabled = config_switch(w2); } else if (strcmpi(w1, "char_movetoused") == 0) { - char_movetoused = config_switch(w2); + charmove_config.char_movetoused = config_switch(w2); } else if (strcmpi(w1, "char_moves_unlimited") == 0) { - char_moves_unlimited = config_switch(w2); + charmove_config.char_moves_unlimited = config_switch(w2); } else if (strcmpi(w1, "import") == 0) { char_config_read(w2); } @@ -5161,6 +2471,21 @@ return 0; } + +/* + * Message conf function + */ +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"); @@ -5176,7 +2501,7 @@ do_final_mapif(); do_final_loginif(); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", ragsrvinfo_db) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", schema_config.ragsrvinfo_db) ) Sql_ShowDebug(sql_handle); char_db_->destroy(char_db_, NULL); @@ -5195,6 +2520,11 @@ ShowStatus("Finished.\n"); } + +void set_server_type(void){ + SERVER_TYPE = ATHENA_SERVER_CHAR; +} + //------------------------------ // Function called when the server // has received a crash signal. @@ -5203,12 +2533,6 @@ { } -void set_server_type(void) -{ - SERVER_TYPE = ATHENA_SERVER_CHAR; -} - - /// Called when a terminate signal is received. void do_shutdown(void) { @@ -5229,23 +2553,29 @@ int do_init(int argc, char **argv) { + login_fd=-1; + char_fd=-1; + fame_list_size_chemist = MAX_FAME_LIST; + fame_list_size_smith = MAX_FAME_LIST; + fame_list_size_taekwon = MAX_FAME_LIST; + //Read map indexes mapindex_init(); - start_point.map = mapindex_name2id("new_zone01"); CHAR_CONF_NAME = "conf/char_athena.conf"; LAN_CONF_NAME = "conf/subnet_athena.conf"; SQL_CONF_NAME = "conf/inter_athena.conf"; MSG_CONF_NAME_EN = "conf/msg_conf/char_msg.conf"; + char_set_defaults(); cli_get_options(argc,argv); - msg_config_read(MSG_CONF_NAME_EN); char_config_read(CHAR_CONF_NAME); char_lan_config_read(LAN_CONF_NAME); sql_config_read(SQL_CONF_NAME); + msg_config_read(MSG_CONF_NAME_EN); - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { + if (strcmp(charserv_config.userid, "s1")==0 && strcmp(charserv_config.passwd, "p1")==0) { ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); @@ -5258,7 +2588,7 @@ mmo_char_sql_init(); char_read_fame_list(); //Read fame lists. - if ((naddr_ != 0) && (!login_ip || !char_ip)) + if ((naddr_ != 0) && (!(charserv_config.login_ip) || !(charserv_config.char_ip) )) { char ip_str[16]; ip2str(addr_[0], ip_str); @@ -5267,13 +2597,13 @@ ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); else ShowStatus("Defaulting to %s as our IP address\n", ip_str); - if (!login_ip) { - safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); - login_ip = str2ip(login_ip_str); + if (!(charserv_config.login_ip) ) { + safestrncpy(charserv_config.login_ip_str, ip_str, sizeof(charserv_config.login_ip_str)); + charserv_config.login_ip = str2ip(charserv_config.login_ip_str); } - if (!char_ip) { - safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); - char_ip = str2ip(char_ip_str); + if (!(charserv_config.char_ip)) { + safestrncpy(charserv_config.char_ip_str, ip_str, sizeof(charserv_config.char_ip_str)); + charserv_config.char_ip = str2ip(charserv_config.char_ip_str); } } @@ -5293,64 +2623,33 @@ //Cleaning the tables for NULL entrys @ startup [Sirius] //Chardb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", schema_config.char_db) ) Sql_ShowDebug(sql_handle); //guilddb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", schema_config.guild_db) ) Sql_ShowDebug(sql_handle); //guildmemberdb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", schema_config.guild_member_db) ) Sql_ShowDebug(sql_handle); set_defaultparse(parse_char); - if( (char_fd = make_listen_bind(bind_ip,char_port)) == -1 ) { - ShowFatalError("Failed to bind to port '"CL_WHITE"%d"CL_RESET"'\n",char_port); + if( (char_fd = make_listen_bind(charserv_config.bind_ip,charserv_config.char_port)) == -1 ) { + ShowFatalError("Failed to bind to port '"CL_WHITE"%d"CL_RESET"'\n",charserv_config.char_port); exit(EXIT_FAILURE); } - ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); - if( runflag != CORE_ST_STOP ) { shutdown_callback = do_shutdown; runflag = CHARSERVER_ST_RUNNING; } - if( console ){ //start listening - add_timer_func_list(parse_console_timer, "parse_console_timer"); - add_timer_interval(gettick()+1000, parse_console_timer, 0, 0, 1000); //start in 1s each 1sec - } - return 0; -} + do_init_charcnslif(); -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); -} + ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", charserv_config.char_port); -/*====================================================== - * 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 \t\tAlternative char-server configuration.\n"); - ShowInfo(" --lan-config \t\tAlternative lag configuration.\n"); - ShowInfo(" --inter-config \t\tAlternative inter-server configuration.\n"); - ShowInfo(" --msg-config \t\tAlternative message configuration.\n"); - if( do_exit ) - exit(EXIT_SUCCESS); + return 0; } Index: src/char/int_storage.c =================================================================== --- src/char/int_storage.c (revision 17367) +++ src/char/int_storage.c (working copy) @@ -41,7 +41,7 @@ StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`"); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); + StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", schema_config.storage_db, account_id); if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) Sql_ShowDebug(sql_handle); @@ -99,7 +99,7 @@ StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`"); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); + StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", schema_config.guild_storage_db, guild_id); if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) Sql_ShowDebug(sql_handle); @@ -146,13 +146,13 @@ // Delete char storage int inter_storage_delete(int account_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", schema_config.storage_db, account_id) ) Sql_ShowDebug(sql_handle); return 0; } int inter_guild_storage_delete(int guild_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_storage_db, guild_id) ) Sql_ShowDebug(sql_handle); return 0; } @@ -162,7 +162,7 @@ int mapif_load_guild_storage(int fd,int account_id,int guild_id, char flag) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_db, guild_id) ) Sql_ShowDebug(sql_handle); else if( Sql_NumRows(sql_handle) > 0 ) {// guild exists @@ -222,7 +222,7 @@ } else { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_db, guild_id) ) Sql_ShowDebug(sql_handle); else if( Sql_NumRows(sql_handle) > 0 ) {// guild exists @@ -266,7 +266,7 @@ StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`"); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'",inventory_db,char_id); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'",schema_config.inventory_db,char_id); stmt = SqlStmt_Malloc(sql_handle); if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) @@ -296,13 +296,13 @@ i++; } } - + if(!i) //No items found - No need to continue return 0; //First we delete the character's items StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE",inventory_db); + StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE",schema_config.inventory_db); for(j=0; j struct auth_node* + +struct online_char_data { + int account_id; + int char_id; + int fd; + int waiting_disconnect; + short server; // -2: unknown server, -1: not connected, 0+: id of server + bool pincode_success; + int version; +}; +DBMap* char_get_onlinedb(); // int account_id -> struct online_char_data* + +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: a@a.com) 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 +}; + +struct mmo_charstatus; +DBMap* char_get_chardb(); // int char_id -> struct mmo_charstatus* + +//Custom limits for the fame lists. [Skotlex] +int fame_list_size_chemist; +int fame_list_size_smith; +int fame_list_size_taekwon; +// 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]; + +#define DEFAULT_AUTOSAVE_INTERVAL 300*1000 +#define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls) + +int search_mapserver(unsigned short map, uint32 ip, uint16 port); +int lan_subnetcheck(uint32 ip); + +int count_users(void); +DBData create_online_char_data(DBKey key, va_list args); +int char_db_setoffline(DBKey key, DBData *data, va_list ap); +void set_char_online(int map_id, int char_id, int account_id); +void set_char_offline(int char_id, int account_id); +void set_all_offline(int id); +void disconnect_player(int account_id); +int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data); + +int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p); +int mmo_char_tosql(int char_id, struct mmo_charstatus* p); +int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything); +int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf); +int delete_char_sql(int char_id); +int rename_char_sql(struct char_session_data *sd, int char_id); +int divorce_char_sql(int partner_id1, int partner_id2); int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch); -int mapif_sendall(unsigned char *buf,unsigned int len); -int mapif_sendallwos(int fd,unsigned char *buf,unsigned int len); -int mapif_send(int fd,unsigned char *buf,unsigned int len); - int char_married(int pl1,int pl2); int char_child(int parent_id, int child_id); int char_family(int pl1,int pl2,int pl3); -int request_accreg2(int account_id, int char_id); -int save_accreg2(unsigned char* buf, int len); +int char_loadName(int char_id, char* name); +int check_char_name(char * name, char * esc_name); -extern int char_name_option; -extern char char_name_letters[]; -extern bool char_gm_read; -extern int autosave_interval; -extern int save_log; -extern char db_path[]; -extern char char_db[256]; -extern char scdata_db[256]; -extern char cart_db[256]; -extern char inventory_db[256]; -extern char charlog_db[256]; -extern char storage_db[256]; -extern char interlog_db[256]; -extern char reg_db[256]; -extern char skill_db[256]; -extern char memo_db[256]; -extern char guild_db[256]; -extern char guild_alliance_db[256]; -extern char guild_castle_db[256]; -extern char guild_expulsion_db[256]; -extern char guild_member_db[256]; -extern char guild_position_db[256]; -extern char guild_skill_db[256]; -extern char guild_storage_db[256]; -extern char party_db[256]; -extern char pet_db[256]; -extern char mail_db[256]; -extern char auction_db[256]; -extern char quest_db[256]; -extern char homunculus_db[256]; -extern char skill_homunculus_db[256]; -extern char mercenary_db[256]; -extern char mercenary_owner_db[256]; -extern char ragsrvinfo_db[256]; +void pincode_decrypt( uint32 userSeed, char* pin ); +int pincode_compare( int fd, struct char_session_data* sd, char* pin ); +void char_auth_ok(int fd, struct char_session_data *sd); +void set_char_charselect(int account_id); +void char_read_fame_list(void); -extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris] +#if PACKETVER >= 20120307 +int make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style); +#else +int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style); +#endif -extern int guild_exp_rate; -extern int log_inter; +//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; } } +#define msg_config_read(cfgName) char_msg_config_read(cfgName) +#define msg_txt(msg_number) char_msg_txt(msg_number) +#define do_final_msg() char_do_final_msg() +int char_msg_config_read(char *cfgName); +const char* char_msg_txt(int msg_number); +void char_do_final_msg(void); + #endif /* _CHAR_SQL_H_ */ Index: src/char/int_mail.c =================================================================== --- src/char/int_mail.c (revision 17367) +++ src/char/int_mail.c (working copy) @@ -9,6 +9,7 @@ #include "../common/sql.h" #include "../common/timer.h" #include "char.h" +#include "char_mapif.h" #include "inter.h" #include @@ -35,7 +36,7 @@ // I keep the `status` < 3 just in case someone forget to apply the sqlfix StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", - mail_db, char_id, MAIL_MAX_INBOX + 1); + schema_config.mail_db, char_id, MAIL_MAX_INBOX + 1); if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) Sql_ShowDebug(sql_handle); @@ -84,7 +85,7 @@ msg = &md->msg[i]; if( msg->status == MAIL_NEW ) { - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) ) + if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", schema_config.mail_db, MAIL_UNREAD, msg->id) ) Sql_ShowDebug(sql_handle); msg->status = MAIL_UNREAD; @@ -108,7 +109,7 @@ // build message save query StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`", mail_db); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`", schema_config.mail_db); for (j = 0; j < MAX_SLOTS; j++) StringBuf_Printf(&buf, ", `card%d`", j); StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%"PRIu64"'", @@ -116,7 +117,7 @@ for (j = 0; j < MAX_SLOTS; j++) StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); StringBuf_AppendStr(&buf, ")"); - + //Unique Non Stackable Item ID updateLastUid(msg->item.unique_id); dbUpdateUid(sql_handle); @@ -153,7 +154,7 @@ "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`"); for( j = 0; j < MAX_SLOTS; j++ ) StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); + StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", schema_config.mail_db, mail_id); if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) @@ -228,7 +229,7 @@ static void mapif_parse_Mail_read(int fd) { int mail_id = RFIFOL(fd,2); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", schema_config.mail_db, MAIL_READ, mail_id) ) Sql_ShowDebug(sql_handle); } @@ -241,7 +242,7 @@ int i; StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); + StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", schema_config.mail_db); for (i = 0; i < MAX_SLOTS; i++) StringBuf_Printf(&buf, ", `card%d` = '0'", i); StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); @@ -297,7 +298,7 @@ static void mapif_Mail_delete(int fd, int char_id, int mail_id) { bool failed = false; - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) + if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", schema_config.mail_db, mail_id) ) { Sql_ShowDebug(sql_handle); failed = true; @@ -322,7 +323,7 @@ void mapif_Mail_new(struct mail_message *msg) { unsigned char buf[74]; - + if( !msg || !msg->id ) return; @@ -346,7 +347,7 @@ { if( msg.dest_id != char_id) return; - else if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) + else if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", schema_config.mail_db, mail_id) ) Sql_ShowDebug(sql_handle); else { @@ -389,7 +390,7 @@ static void mapif_Mail_send(int fd, struct mail_message* msg) { int len = sizeof(struct mail_message) + 4; - + WFIFOHEAD(fd,len); WFIFOW(fd,0) = 0x384d; WFIFOW(fd,2) = len; @@ -411,7 +412,7 @@ // Try to find the Dest Char by Name Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", schema_config.char_db, esc_name) ) Sql_ShowDebug(sql_handle); else if ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) Index: src/char/int_homun.c =================================================================== --- src/char/int_homun.c (revision 17367) +++ src/char/int_homun.c (working copy) @@ -95,7 +95,7 @@ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " "(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " "VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + schema_config.homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize) ) { Sql_ShowDebug(sql_handle); @@ -109,7 +109,7 @@ else { if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + schema_config.homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id) ) { Sql_ShowDebug(sql_handle); @@ -121,7 +121,7 @@ int i; stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", skill_homunculus_db, hd->hom_id) ) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", schema_config.skill_homunculus_db, hd->hom_id) ) SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_HOMUNSKILL; ++i ) { @@ -156,7 +156,8 @@ memset(hd, 0, sizeof(*hd)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", homunculus_db, homun_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", + schema_config.homunculus_db, homun_id) ) { Sql_ShowDebug(sql_handle); return false; @@ -202,7 +203,7 @@ hd->hunger = cap_value(hd->hunger, 0, 100); // Load Homunculus Skill - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", skill_homunculus_db, homun_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", schema_config.skill_homunculus_db, homun_id) ) { Sql_ShowDebug(sql_handle); return false; @@ -223,7 +224,7 @@ } Sql_FreeResult(sql_handle); - if( save_log ) + if( charserv_config.save_log ) ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); return true; @@ -231,8 +232,8 @@ bool mapif_homunculus_delete(int homun_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", homunculus_db, homun_id) - || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", skill_homunculus_db, homun_id) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", schema_config.homunculus_db, homun_id) + || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", schema_config.skill_homunculus_db, homun_id) ) { Sql_ShowDebug(sql_handle); return false; @@ -245,16 +246,16 @@ int i; // Check Authorised letters/symbols in the name of the homun - if( char_name_option == 1 ) + if( charserv_config.char_name_option == 1 ) {// only letters/symbols in char_name_letters are authorised for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) + if( strchr(charserv_config.char_name_letters, name[i]) == NULL ) return false; } else - if( char_name_option == 2 ) + if( charserv_config.char_name_option == 2 ) {// letters/symbols in char_name_letters are forbidden for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) + if( strchr(charserv_config.char_name_letters, name[i]) != NULL ) return false; } Index: src/char/Makefile.in =================================================================== --- src/char/Makefile.in (revision 17367) +++ src/char/Makefile.in (working copy) @@ -15,12 +15,14 @@ COMMON_SQL_OBJ = ../common/obj_sql/sql.o COMMON_H = ../common/sql.h -CHAR_OBJ = obj_sql/char.o obj_sql/inter.o obj_sql/int_party.o obj_sql/int_guild.o \ - obj_sql/int_storage.o obj_sql/int_pet.o obj_sql/int_homun.o obj_sql/int_mail.o obj_sql/int_auction.o obj_sql/int_quest.o obj_sql/int_mercenary.o obj_sql/int_elemental.o -CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h int_auction.h int_quest.h int_mercenary.h int_elemental.h +CHAR_OBJ = char.o char_clif.o char_logif.o char_mapif.o char_cnslif.o\ + inter.o int_party.o int_guild.o int_storage.o int_pet.o int_homun.o int_mail.o int_auction.o int_quest.o int_mercenary.o int_elemental.o +CHAR_H = char.h \ + inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h int_auction.h int_quest.h int_mercenary.h int_elemental.h +CHAR_SQL_OBJ = $(CHAR_OBJ:%=obj_sql/%) HAVE_MYSQL=@HAVE_MYSQL@ -ifeq ($(HAVE_MYSQL),yes) +ifeq ($(HAVE_MYSQL),yes) SQL_DEPENDS=char-server_sql else SQL_DEPENDS=needs_mysql @@ -49,9 +51,9 @@ ##################################################################### -char-server_sql: obj_sql $(CHAR_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) +char-server_sql: obj_sql $(CHAR_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) @echo " LD $@" - @@CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@ + @@CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@ needs_mysql: @echo "MySQL not found or disabled by the configure script" Index: src/char/int_pet.c =================================================================== --- src/char/int_pet.c (revision 17367) +++ src/char/int_pet.c (working copy) @@ -32,7 +32,7 @@ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + schema_config.pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate) ) { Sql_ShowDebug(sql_handle); @@ -43,7 +43,7 @@ else {// Update pet. if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + schema_config.pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id) ) { Sql_ShowDebug(sql_handle); @@ -51,7 +51,7 @@ } } - if (save_log) + if (charserv_config.save_log) ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); return 1; } @@ -68,7 +68,7 @@ //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", schema_config.pet_db, pet_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -94,7 +94,7 @@ p->hungry = cap_value(p->hungry, 0, 100); p->intimate = cap_value(p->intimate, 0, 1000); - if( save_log ) + if( charserv_config.save_log ) ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); } return 0; @@ -114,7 +114,7 @@ int inter_pet_delete(int pet_id){ ShowInfo("delete pet request: %d...\n",pet_id); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", schema_config.pet_db, pet_id) ) Sql_ShowDebug(sql_handle); return 0; } Index: src/char/int_quest.c =================================================================== --- src/char/int_quest.c (revision 17367) +++ src/char/int_quest.c (working copy) @@ -34,7 +34,7 @@ memset(&tmp_quest, 0, sizeof(struct quest)); - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.quest_db, MAX_QUEST_DB) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) @@ -55,7 +55,7 @@ //Delete a quest bool mapif_quest_delete(int char_id, int quest_id) { - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id) ) + if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", schema_config.quest_db, quest_id, char_id) ) { Sql_ShowDebug(sql_handle); return false; @@ -67,7 +67,7 @@ //Add a quest to a questlog bool mapif_quest_add(int char_id, struct quest qd) { - if ( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) ) + if ( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", schema_config.quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) ) { Sql_ShowDebug(sql_handle); return false; @@ -79,7 +79,7 @@ //Update a questlog bool mapif_quest_update(int char_id, struct quest qd) { - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) ) + if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", schema_config.quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) ) { Sql_ShowDebug(sql_handle); return false; Index: src/char/int_auction.c =================================================================== --- src/char/int_auction.c (revision 17367) +++ src/char/int_auction.c (working copy) @@ -10,6 +10,7 @@ #include "../common/sql.h" #include "../common/timer.h" #include "char.h" +#include "char_mapif.h" #include "inter.h" #include "int_mail.h" #include "int_auction.h" @@ -50,7 +51,7 @@ StringBuf_Init(&buf); StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", - auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + schema_config.auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); for( j = 0; j < MAX_SLOTS; j++ ) StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); @@ -81,7 +82,7 @@ auction->timestamp = time(NULL) + (auction->hours * 3600); StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`", auction_db); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`", schema_config.auction_db); for( j = 0; j < MAX_SLOTS; j++ ) StringBuf_Printf(&buf, ",`card%d`", j); StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d','%"PRIu64"'", @@ -165,7 +166,7 @@ { unsigned int auction_id = auction->auction_id; - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", schema_config.auction_db, auction_id) ) Sql_ShowDebug(sql_handle); if( auction->auction_end_timer != INVALID_TIMER ) @@ -189,7 +190,7 @@ "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`"); for( i = 0; i < MAX_SLOTS; i++ ) StringBuf_Printf(&buf, ",`card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); + StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", schema_config.auction_db); if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) Sql_ShowDebug(sql_handle); Index: src/char/int_guild.c =================================================================== --- src/char/int_guild.c (revision 17367) +++ src/char/int_guild.c (working copy) @@ -10,6 +10,7 @@ #include "../common/strlib.h" #include "../common/timer.h" #include "char.h" +#include "char_mapif.h" #include "inter.h" #include "int_guild.h" @@ -72,7 +73,7 @@ if( g->save_flag == GS_REMOVE ) {// Nothing to save, guild is ready for removal. - if (save_log) + if (charserv_config.save_log) ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); db_remove(guild_db_, key); } @@ -84,15 +85,15 @@ state = guild_db_->size(guild_db_); if( state < 1 ) state = 1; //Calculate the time slot for the next save. - add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); + add_timer(tick + (charserv_config.autosave_interval)/state, guild_save_timer, 0, 0); return 0; } int inter_guild_removemember_tosql(int account_id, int char_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", schema_config.guild_member_db, account_id, char_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", schema_config.char_db, char_id) ) Sql_ShowDebug(sql_handle); return 0; } @@ -140,7 +141,7 @@ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", - guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) + schema_config.guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) { Sql_ShowDebug(sql_handle); if (g->guild_id == -1) @@ -160,7 +161,7 @@ bool add_comma = false; StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); + StringBuf_Printf(&buf, "UPDATE `%s` SET ", schema_config.guild_db); if (flag & GS_EMBLEM) { @@ -240,14 +241,14 @@ Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", - guild_member_db, g->guild_id, m->account_id, m->char_id, + schema_config.guild_member_db, g->guild_id, m->account_id, m->char_id, m->hair, m->hair_color, m->gender, m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name) ) Sql_ShowDebug(sql_handle); if (m->modified&GS_MEMBER_NEW || new_guild == 1) { if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", - char_db, g->guild_id, m->char_id) ) + schema_config.char_db, g->guild_id, m->char_id) ) Sql_ShowDebug(sql_handle); } m->modified = GS_MEMBER_UNMODIFIED; @@ -264,7 +265,7 @@ continue; Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", - guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode) ) + schema_config.guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode) ) Sql_ShowDebug(sql_handle); p->modified = GS_POSITION_UNMODIFIED; } @@ -277,7 +278,7 @@ // their info changed, not to mention this would also mess up oppositions! // [Skotlex] //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_alliance_db, g->guild_id) ) { Sql_ShowDebug(sql_handle); } @@ -292,7 +293,7 @@ Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " "VALUES ('%d','%d','%d','%s')", - guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name) ) + schema_config.guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name) ) Sql_ShowDebug(sql_handle); } } @@ -310,7 +311,7 @@ Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " - "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes) ) + "VALUES ('%d','%d','%s','%s')", schema_config.guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes) ) Sql_ShowDebug(sql_handle); } } @@ -322,13 +323,13 @@ for(i=0;iskill[i].id>0 && g->skill[i].lv>0){ if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", - guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv) ) + schema_config.guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv) ) Sql_ShowDebug(sql_handle); } } } - if (save_log) + if (charserv_config.save_log) ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); return 1; } @@ -354,7 +355,7 @@ #endif if( SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " - "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id) ) + "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", schema_config.guild_db, schema_config.char_db, guild_id) ) { Sql_ShowDebug(sql_handle); return NULL; @@ -409,7 +410,7 @@ // load guild member info if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " - "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id) ) + "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", schema_config.guild_member_db, guild_id) ) { Sql_ShowDebug(sql_handle); aFree(g); @@ -437,7 +438,7 @@ } //printf("- Read guild_position %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_position_db, guild_id) ) { Sql_ShowDebug(sql_handle); aFree(g); @@ -459,7 +460,7 @@ } //printf("- Read guild_alliance %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_alliance_db, guild_id) ) { Sql_ShowDebug(sql_handle); aFree(g); @@ -475,7 +476,7 @@ } //printf("- Read guild_expulsion %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_expulsion_db, guild_id) ) { Sql_ShowDebug(sql_handle); aFree(g); @@ -491,7 +492,7 @@ } //printf("- Read guild_skill %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", schema_config.guild_skill_db, guild_id) ) { Sql_ShowDebug(sql_handle); aFree(g); @@ -516,7 +517,7 @@ idb_put(guild_db_, guild_id, g); //Add to cache g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. - if (save_log) + if (charserv_config.save_log) ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); return g; @@ -530,15 +531,15 @@ StringBuf_Init(&buf); StringBuf_Printf(&buf, "REPLACE INTO `%s` SET `castle_id`='%d', `guild_id`='%d', `economy`='%d', `defense`='%d', " - "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", - guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, - gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); + "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", + schema_config.guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, + gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); for (i = 0; i < MAX_GUARDIANS; ++i) StringBuf_Printf(&buf, ", `visibleG%d`='%d'", i, gc->guardian[i].visible); if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) Sql_ShowDebug(sql_handle); - else if(save_log) + else if(charserv_config.save_log) ShowInfo("Saved guild castle (%d)\n", gc->castle_id); StringBuf_Destroy(&buf); @@ -561,7 +562,7 @@ "`triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`"); for (i = 0; i < MAX_GUARDIANS; ++i) StringBuf_Printf(&buf, ", `visibleG%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", guild_castle_db, castle_id); + StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", schema_config.guild_castle_db, castle_id); if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { Sql_ShowDebug(sql_handle); StringBuf_Destroy(&buf); @@ -590,7 +591,7 @@ idb_put(castle_db, castle_id, gc); - if (save_log) + if (charserv_config.save_log) ShowInfo("Loaded guild castle (%d - guild %d)\n", castle_id, gc->guild_id); return gc; @@ -619,7 +620,7 @@ if (guild_id == -1) { //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", schema_config.char_db, char_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -670,7 +671,7 @@ if (guild_id == -1) { //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", schema_config.char_db, char_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -760,7 +761,7 @@ Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); //Lookup guilds with the same name - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", schema_config.guild_db, esc_name) ) { Sql_ShowDebug(sql_handle); return -1; @@ -1142,15 +1143,15 @@ return 0; } // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + if (charserv_config.char_name_option == 1) { // only letters/symbols in char_name_letters are authorised for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { + if (strchr(charserv_config.char_name_letters, name[i]) == NULL) { mapif_guild_created(fd,account_id,NULL); return 0; } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + } else if (charserv_config.char_name_option == 2) { // letters/symbols in char_name_letters are forbidden for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { + if (strchr(charserv_config.char_name_letters, name[i]) != NULL) { mapif_guild_created(fd,account_id,NULL); return 0; } @@ -1200,7 +1201,7 @@ mapif_guild_created(fd,account_id,g); mapif_guild_info(fd,g); - if(log_inter) + if(charserv_config.log_inter) inter_log("guild %s (id=%d) created by master %s (id=%d)\n", name, g->guild_id, master->name, master->account_id ); @@ -1266,7 +1267,7 @@ if( g == NULL ) { // Unknown guild, just update the player - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", schema_config.char_db, account_id, char_id) ) Sql_ShowDebug(sql_handle); // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); return 0; @@ -1379,37 +1380,37 @@ // Delete guild from sql //printf("- Delete guild %d from guild\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", schema_config.guild_db, guild_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", schema_config.guild_member_db, guild_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", schema_config.guild_castle_db, guild_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", schema_config.guild_storage_db, guild_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", schema_config.guild_alliance_db, guild_id, guild_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", schema_config.guild_position_db, guild_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", schema_config.guild_skill_db, guild_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", schema_config.guild_expulsion_db, guild_id) ) Sql_ShowDebug(sql_handle); //printf("- Update guild %d of char\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", schema_config.char_db, guild_id) ) Sql_ShowDebug(sql_handle); mapif_guild_broken(guild_id,0); - if(log_inter) + if(charserv_config.log_inter) inter_log("guild %s (id=%d) broken\n",g->name,guild_id); //Remove the guild from memory. [Skotlex] @@ -1497,8 +1498,8 @@ exp = g->member[i].exp - old_exp; // Compute gained exp - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; + if (charserv_config.guild_exp_rate != 100) + exp = exp*(charserv_config.guild_exp_rate)/100; // Update guild exp if (exp > UINT64_MAX - g->exp) @@ -1759,7 +1760,7 @@ switch (index) { case 1: - if (log_inter && gc->guild_id != value) { + if (charserv_config.log_inter && gc->guild_id != value) { int gid = (value) ? value : gc->guild_id; struct guild *g = idb_get(guild_db_, gid); inter_log("guild %s (id=%d) %s castle id=%d\n", Index: src/char/int_elemental.c =================================================================== --- src/char/int_elemental.c (revision 17367) +++ src/char/int_elemental.c (working copy) @@ -17,7 +17,7 @@ bool mapif_elemental_save(struct s_elemental* ele) { bool flag = true; - + if( ele->elemental_id == 0 ) { // Create new DB entry if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`atk1`,`atk2`,`matk`,`aspd`,`def`,`mdef`,`flee`,`hit`,`life_time`)" @@ -44,23 +44,23 @@ bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) { char* data; - + memset(ele, 0, sizeof(struct s_elemental)); ele->elemental_id = ele_id; ele->char_id = char_id; - + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `atk1`, `atk2`, `matk`, `aspd`," "`def`, `mdef`, `flee`, `hit`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", ele_id, char_id) ) { Sql_ShowDebug(sql_handle); return false; } - + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) { Sql_FreeResult(sql_handle); return false; } - + Sql_GetData(sql_handle, 0, &data, NULL); ele->class_ = atoi(data); Sql_GetData(sql_handle, 1, &data, NULL); ele->mode = atoi(data); Sql_GetData(sql_handle, 2, &data, NULL); ele->hp = atoi(data); @@ -77,9 +77,9 @@ Sql_GetData(sql_handle, 13, &data, NULL); ele->hit = atoi(data); Sql_GetData(sql_handle, 14, &data, NULL); ele->life_time = atoi(data); Sql_FreeResult(sql_handle); - if( save_log ) + if( charserv_config.save_log ) ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); - + return true; } @@ -88,13 +88,13 @@ Sql_ShowDebug(sql_handle); return false; } - + return true; } static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) { int size = sizeof(struct s_elemental) + 5; - + WFIFOHEAD(fd,size); WFIFOW(fd,0) = 0x387c; WFIFOW(fd,2) = size; @@ -150,7 +150,7 @@ *------------------------------------------*/ int inter_elemental_parse_frommap(int fd) { unsigned short cmd = RFIFOW(fd,0); - + switch( cmd ) { case 0x307c: mapif_parse_elemental_create(fd, (struct s_elemental*)RFIFOP(fd,4)); break; case 0x307d: mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; Index: src/char/inter.c =================================================================== --- src/char/inter.c (revision 17367) +++ src/char/inter.c (working copy) @@ -9,6 +9,8 @@ #include "../common/socket.h" #include "../common/timer.h" #include "char.h" +#include "char_logif.h" +#include "char_mapif.h" #include "inter.h" #include "int_party.h" #include "int_guild.h" @@ -389,7 +391,7 @@ account_id = atoi(query); if (account_id < START_ACCOUNT_NUM) { // is string - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `%s` WHERE `name` LIKE '%s' LIMIT 10", char_db, query_esq) + if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `%s` WHERE `name` LIKE '%s' LIMIT 10", schema_config.char_db, query_esq) || Sql_NumRows(sql_handle) == 0 ) { if( Sql_NumRows(sql_handle) == 0 ) { inter_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); @@ -523,12 +525,12 @@ switch( type ) { case 3: //Char Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", schema_config.reg_db, char_id) ) Sql_ShowDebug(sql_handle); account_id = 0; break; case 2: //Account Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", schema_config.reg_db, account_id) ) Sql_ShowDebug(sql_handle); char_id = 0; break; @@ -544,7 +546,7 @@ return 0; StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", schema_config.reg_db); for( i = 0; i < reg->reg_num; ++i ) { r = ®->reg[i]; @@ -590,11 +592,11 @@ switch( type ) { case 3: //char reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", schema_config.reg_db, char_id) ) Sql_ShowDebug(sql_handle); break; case 2: //account reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", schema_config.reg_db, account_id) ) Sql_ShowDebug(sql_handle); break; case 1: //account2 reg @@ -669,7 +671,7 @@ else if(!strcmpi(w1,"party_share_level")) party_share_level = atoi(w2); else if(!strcmpi(w1,"log_inter")) - log_inter = atoi(w2); + charserv_config.log_inter = atoi(w2); else if(!strcmpi(w1,"import")) inter_config_read(w2); } @@ -692,7 +694,7 @@ va_end(ap); Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str) ) + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", schema_config.interlog_db, esc_str) ) Sql_ShowDebug(sql_handle); return 0; @@ -934,7 +936,7 @@ safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", schema_config.char_db, esc_name) ) Sql_ShowDebug(sql_handle); // search if character exists before to ask all map-servers @@ -1088,15 +1090,15 @@ name = (char*)RFIFOP(fd,11); // Check Authorised letters/symbols in the name - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + if (charserv_config.char_name_option == 1) { // only letters/symbols in char_name_letters are authorised for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { + if (strchr(charserv_config.char_name_letters, name[i]) == NULL) { mapif_namechange_ack(fd, account_id, char_id, type, 0, name); return 0; } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + } else if (charserv_config.char_name_option == 2) { // letters/symbols in char_name_letters are forbidden for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { + if (strchr(charserv_config.char_name_letters, name[i]) != NULL) { mapif_namechange_ack(fd, account_id, char_id, type, 0, name); return 0; } Index: src/char/CMakeLists.txt =================================================================== --- src/char/CMakeLists.txt (revision 17367) +++ src/char/CMakeLists.txt (working copy) @@ -12,6 +12,10 @@ message( STATUS "Creating target char-server_sql" ) set( SQL_CHAR_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/char.h" + "${CMAKE_CURRENT_SOURCE_DIR}/char_clif.h" + "${CMAKE_CURRENT_SOURCE_DIR}/char_cnslif.h" + "${CMAKE_CURRENT_SOURCE_DIR}/char_logif.h" + "${CMAKE_CURRENT_SOURCE_DIR}/char_mapif.h" "${CMAKE_CURRENT_SOURCE_DIR}/int_auction.h" "${CMAKE_CURRENT_SOURCE_DIR}/int_elemental.h" "${CMAKE_CURRENT_SOURCE_DIR}/int_guild.h" @@ -26,6 +30,10 @@ ) set( SQL_CHAR_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/char.c" + "${CMAKE_CURRENT_SOURCE_DIR}/char_clif.c" + "${CMAKE_CURRENT_SOURCE_DIR}/char_cnslif.c" + "${CMAKE_CURRENT_SOURCE_DIR}/char_logif.c" + "${CMAKE_CURRENT_SOURCE_DIR}/char_mapif.c" "${CMAKE_CURRENT_SOURCE_DIR}/int_auction.c" "${CMAKE_CURRENT_SOURCE_DIR}/int_elemental.c" "${CMAKE_CURRENT_SOURCE_DIR}/int_guild.c" Index: src/char/int_mercenary.c =================================================================== --- src/char/int_mercenary.c (revision 17367) +++ src/char/int_mercenary.c (working copy) @@ -19,7 +19,7 @@ { char* data; - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", schema_config.mercenary_owner_db, char_id) ) { Sql_ShowDebug(sql_handle); return false; @@ -46,7 +46,7 @@ bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status) { if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith) ) + schema_config.mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith) ) { Sql_ShowDebug(sql_handle); return false; @@ -57,10 +57,10 @@ bool mercenary_owner_delete(int char_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", schema_config.mercenary_owner_db, char_id) ) Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_db, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", schema_config.mercenary_db, char_id) ) Sql_ShowDebug(sql_handle); return true; @@ -74,7 +74,7 @@ { // Create new DB entry if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time) ) + schema_config.mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time) ) { Sql_ShowDebug(sql_handle); flag = false; @@ -84,7 +84,7 @@ } else if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id) ) + schema_config.mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id) ) { // Update DB entry Sql_ShowDebug(sql_handle); flag = false; @@ -101,7 +101,7 @@ merc->mercenary_id = merc_id; merc->char_id = char_id; - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", mercenary_db, merc_id, char_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", schema_config.mercenary_db, merc_id, char_id) ) { Sql_ShowDebug(sql_handle); return false; @@ -119,15 +119,15 @@ Sql_GetData(sql_handle, 3, &data, NULL); merc->kill_count = atoi(data); Sql_GetData(sql_handle, 4, &data, NULL); merc->life_time = atoi(data); Sql_FreeResult(sql_handle); - if( save_log ) + if( charserv_config.save_log ) ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); - + return true; } bool mapif_mercenary_delete(int merc_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", mercenary_db, merc_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", schema_config.mercenary_db, merc_id) ) { Sql_ShowDebug(sql_handle); return false; Index: src/common/mmo.h =================================================================== --- src/common/mmo.h (revision 17367) +++ src/common/mmo.h (working copy) @@ -8,52 +8,19 @@ #include "../common/db.h" #include -// 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 //Remove/Comment this line to disable sc_data saving. [Skotlex] -#define ENABLE_SC_SAVING +//#define ENABLE_SC_SAVING +#ifndef ENABLE_SC_SAVING + #ifdef NEW_CARTS + #warning "Cart won't be able to be saved for relog\n" + #endif +#endif //Remove/Comment this line to disable server-side hot-key saving support [Skotlex] //Note that newer clients no longer save hotkeys in the registry! #define HOTKEY_SAVING Index: src/common/cli.c =================================================================== --- src/common/cli.c (revision 17367) +++ src/common/cli.c (working copy) @@ -53,12 +53,12 @@ */ void display_versionscreen(bool do_exit) { - ShowInfo(CL_WHITE"rAthena SVN version: %s" CL_RESET"\n", get_svn_revision()); - ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://rathena.org/\n"); - ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.rizon.net/#rathena\n"); - ShowInfo("Open "CL_WHITE"readme.txt"CL_RESET" for more information.\n"); - if (do_exit) - exit(EXIT_SUCCESS); + ShowInfo(CL_WHITE"rAthena SVN version: %s" CL_RESET"\n", get_svn_revision()); + ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://rathena.org/\n"); + ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.rizon.net/#rathena\n"); + ShowInfo("Open "CL_WHITE"readme.txt"CL_RESET" for more information.\n"); + if (do_exit) + exit(EXIT_SUCCESS); } /* Index: src/common/cli.h =================================================================== --- src/common/cli.h (revision 17367) +++ src/common/cli.h (working copy) @@ -32,6 +32,8 @@ extern char* MSG_CONF_NAME_EN; //all extern void display_helpscreen(bool exit); +void display_versionscreen(bool do_exit); +bool opt_has_next_value(const char* option, int i, int argc); int cli_get_options(int argc, char ** argv); int parse_console_timer(int tid, unsigned int tick, int id, intptr_t data); extern int parse_console(const char* buf); //particular for each serv Index: src/common/timer.c =================================================================== --- src/common/timer.c (revision 17367) +++ 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 17367) +++ src/common/timer.h (working copy) @@ -5,6 +5,7 @@ #define _TIMER_H_ #include "../common/cbasetypes.h" +#include #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/socket.c =================================================================== --- src/common/socket.c (revision 17367) +++ src/common/socket.c (working copy) @@ -18,7 +18,7 @@ #include "../common/winapi.h" #else #include - #include + #include #include #include #include @@ -637,7 +637,7 @@ /// advance the RFIFO cursor (marking 'len' bytes as processed) int RFIFOSKIP(int fd, size_t len) { - struct socket_data *s; + struct socket_data *s; if ( !session_isActive(fd) ) return 0; Index: conf/login_athena.conf =================================================================== --- conf/login_athena.conf (revision 17367) +++ conf/login_athena.conf (working copy) @@ -82,8 +82,21 @@ 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 +// Client MD5 hash check +// 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: no + +// 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: 98, cb1ea78023d337c38e8ba5124e2338ae +client_hash: 99, any + // Store passwords as MD5 hashes instead of plaintext ? // NOTE: Will not work with clients that use use_MD5_passwords: no @@ -145,17 +158,5 @@ //account.sql.account_db: login //account.sql.accreg_db: global_reg_value -// Client MD5 hash check -// 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 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 - import: conf/inter_athena.conf import: conf/import/login_conf.txt