From 4b434fa6693e73b772d74d8b6f69bbe3e8e5b543 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Mon, 2 Jul 2018 17:28:58 +0700 Subject: [PATCH] Improved `char_del_option` * Renamed to `char_deletion_code` and moved to login_athena.conf * The value is now using column name instead the number, available options are: * `email` (except a@a.com), * `birthday` (YYMMDD), * `pincode`, * and the last is `Sub-query` which allows you to defines your custom deletion code (as example you ask user for secret code while registering an account, or one-time-password for character deletion) * Extends E-mail length from 39 to 49 * Reordering `0x2717` to make notation with variable length be on last --- conf/char_athena.conf | 12 ----- conf/login_athena.conf | 12 +++++ doc/packet_interserv.txt | 11 +++-- sql-files/main.sql | 2 +- sql-files/upgrades/email_extends.sql | 1 + src/char/char.cpp | 15 +----- src/char/char.hpp | 11 ++--- src/char/char_clif.cpp | 70 +++++++++++----------------- src/char/char_logif.cpp | 29 ++++++------ src/login/account.cpp | 56 +++++++++++++++------- src/login/account.hpp | 5 +- src/login/login.cpp | 12 ++++- src/login/login.hpp | 2 + src/login/loginchrif.cpp | 58 +++++++++-------------- 14 files changed, 148 insertions(+), 148 deletions(-) create mode 100644 sql-files/upgrades/email_extends.sql diff --git a/conf/char_athena.conf b/conf/char_athena.conf index a99d61632b..d0e40a0131 100644 --- a/conf/char_athena.conf +++ b/conf/char_athena.conf @@ -170,18 +170,6 @@ char_del_level: 0 // NOTE: Requires client 2010-08-03aragexeRE or newer. char_del_delay: 86400 -// Restrict character deletion by email address or birthdate. -// This restricts players from changing the langtype and deleting characters. -// Defaults based on client date. -// 1: Email address -// 2: Birthdate -// 3: Email address or Birthdate -// IMPORTANT! -// - This config only works for clients that send 0x0068 or 0x01fb for delete request. -// - Use langtype 1 for newer clients (2013+), to use 0x01fb. -// - Clients that are not using 0x0068 or 0x01fb, only use birthdate (YYMMDD) as default. -char_del_option: 2 - // Restrict character deletion as long as he is still in a party or guild // 0: No restriction is applied // 1: Character cannot be deleted as long as he remains in a party diff --git a/conf/login_athena.conf b/conf/login_athena.conf index 969b83bda2..177f3921bb 100644 --- a/conf/login_athena.conf +++ b/conf/login_athena.conf @@ -110,6 +110,18 @@ start_limited_time: -1 // NOTE: Will not work with clients that use use_MD5_passwords: no +// Available values, choose one +// `email` : Email address +// `birthdate` : Birthdate (YYMMDD of birthdate, YY is last 2 digit of birth year) +// `pincode` : Pincode (pin that used in login) +// (Sub-query) : EXPERT ONLY +// +// IMPORTANT! +// - Length of confirmation code which is sent by client depends on its packet +// - Packet 0x0068 is 39 chars, 0x01fb is 49 chars, while 0x0829 only 6 chars. +// - For 2013 clients must use langtype 1 to uses 0x01fb +char_deletion_code: `birthdate` + // Ipban features ipban_enable: yes // Dynamic password failure ipban system diff --git a/doc/packet_interserv.txt b/doc/packet_interserv.txt index 5065298a43..5933141b3f 100644 --- a/doc/packet_interserv.txt +++ b/doc/packet_interserv.txt @@ -89,22 +89,23 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket. 0x2717 Type: AH - Structure: .W .L .40B .L .B .B .11B .5B .L .B .B .B - index: 0,2,6,46,50,51,52,63,68,72,73,74 + Structure: .W .L .L .B .B .L .B .B .B .50S .11S .5S .50S + index: 0,2,6,10,11,12,16,17,18,19,69,80,85 len: 75 parameter: - cmd: packet identification (0x2717) - aid: account identification - - email: email of aid - expiration_time: unknow @FIXME - group_id: the group the aid belong too - char_slots: number of slot available the account have (will be displayed on client) - - birthdate: birthdate of aid - - pincode: current pincode of aid - pincode_change: new pincode of aid - isvip: if this aid is currently vip or not - char_vip: number of charslot that are vip (could only do creation on if you are vip) - MAX_CHAR_BILLING: number of charslort that are for billing + - email: email of aid + - birthdate: birthdate of aid + - pincode: current pincode of aid + - deletion_code: code used for deleting character desc: - Request account data diff --git a/sql-files/main.sql b/sql-files/main.sql index d8c0f00cd7..762523e34b 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -705,7 +705,7 @@ CREATE TABLE IF NOT EXISTS `login` ( `userid` varchar(23) NOT NULL default '', `user_pass` varchar(32) NOT NULL default '', `sex` enum('M','F','S') NOT NULL default 'M', - `email` varchar(39) NOT NULL default '', + `email` varchar(49) NOT NULL default '', `group_id` tinyint(3) NOT NULL default '0', `state` int(11) unsigned NOT NULL default '0', `unban_time` int(11) unsigned NOT NULL default '0', diff --git a/sql-files/upgrades/email_extends.sql b/sql-files/upgrades/email_extends.sql new file mode 100644 index 0000000000..3f6e09edcc --- /dev/null +++ b/sql-files/upgrades/email_extends.sql @@ -0,0 +1 @@ +ALTER TABLE `login` MODIFY COLUMN `email` VARCHAR(49) NULL DEFAULT ''; diff --git a/src/char/char.cpp b/src/char/char.cpp index af1ade357d..b752621364 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include "../common/cbasetypes.hpp" @@ -2704,11 +2704,6 @@ void char_set_defaults(){ charserv_config.char_config.char_per_account = 0; //Maximum chars per account (default unlimited) [Sirius] charserv_config.char_config.char_del_level = 0; //From which level u can delete character [Lupus] charserv_config.char_config.char_del_delay = 86400; -#if PACKETVER >= 20100803 - charserv_config.char_config.char_del_option = CHAR_DEL_BIRTHDATE; -#else - charserv_config.char_config.char_del_option = CHAR_DEL_EMAIL; -#endif charserv_config.char_config.char_del_restriction = CHAR_DEL_RESTRICT_ALL; // charserv_config.userid[24]; @@ -2996,8 +2991,6 @@ bool char_config_read(const char* cfgName, bool normal){ charserv_config.char_config.char_del_level = atoi(w2); } else if (strcmpi(w1, "char_del_delay") == 0) { charserv_config.char_config.char_del_delay = atoi(w2); - } else if (strcmpi(w1, "char_del_option") == 0) { - charserv_config.char_config.char_del_option = atoi(w2); } else if (strcmpi(w1, "char_del_restriction") == 0) { charserv_config.char_config.char_del_restriction = atoi(w2); } else if (strcmpi(w1, "char_rename_party") == 0) { @@ -3080,12 +3073,6 @@ bool char_config_read(const char* cfgName, bool normal){ * Checks for values out of range. */ void char_config_adjust() { -#if PACKETVER < 20100803 - if (charserv_config.char_config.char_del_option&CHAR_DEL_BIRTHDATE) { - ShowWarning("conf/char_athena.conf:char_del_option birthdate is enabled but it requires PACKETVER 2010-08-03 or newer, defaulting to email...\n"); - charserv_config.char_config.char_del_option &= ~CHAR_DEL_BIRTHDATE; - } -#endif } /* diff --git a/src/char/char.hpp b/src/char/char.hpp index 0012f5128c..a9ce5ef65d 100644 --- a/src/char/char.hpp +++ b/src/char/char.hpp @@ -4,6 +4,8 @@ #ifndef _CHAR_HPP_ #define _CHAR_HPP_ +#include + #include "../common/core.hpp" // CORE_ST_LAST #include "../common/mmo.hpp" #include "../common/msg_conf.hpp" @@ -22,11 +24,6 @@ enum E_CHARSERVER_ST { CHARSERVER_ST_LAST }; -enum e_char_delete { - CHAR_DEL_EMAIL = 1, - CHAR_DEL_BIRTHDATE -}; - enum e_char_delete_restriction { CHAR_DEL_RESTRICT_PARTY = 1, CHAR_DEL_RESTRICT_GUILD, @@ -133,7 +130,6 @@ struct Char_Config { char unknown_char_name[NAME_LENGTH]; // Name to use when the requested name cannot be determined char char_name_letters[1024]; // list of letters/symbols allowed (or not) in a character name. by [Yor] int char_name_option; // 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] - int char_del_option; // Character deletion type, email = 1, birthdate = 2 (default) int char_del_restriction; // Character deletion restriction (0: none, 1: if the character is in a party, 2: if the character is in a guild, 3: if the character is in a party or a guild) bool char_rename_party; // Character renaming in a party bool char_rename_guild; // Character renaming in a guild @@ -229,7 +225,7 @@ struct char_session_data { bool auth; // whether the session is authed or not uint32 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] + char email[49+1]; // 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; // total number of characters that can be created @@ -249,6 +245,7 @@ struct char_session_data { time_t unban_time[MAX_CHARS]; int charblock_timer; uint8 flag; // &1 - Retrieving guild bound items + std::string deletion_passcode; }; diff --git a/src/char/char_clif.cpp b/src/char/char_clif.cpp index 3afff1afc3..fcf853ebbe 100644 --- a/src/char/char_clif.cpp +++ b/src/char/char_clif.cpp @@ -4,7 +4,7 @@ #include "char_clif.hpp" #include -#include +#include #include "../common/malloc.hpp" #include "../common/mapindex.hpp" @@ -535,58 +535,40 @@ int chclif_parse_char_delete2_req(int fd, struct char_session_data* sd) { /** * Check char deletion code * @param sd - * @param delcode E-mail or birthdate - * @param flag Delete flag + * @param char_id Requested Char ID + * @param delcode Deletion code from cleint * @return true:Success, false:Failure **/ -bool chclif_delchar_check(struct char_session_data *sd, char *delcode, uint8 flag) { - // E-Mail check - if (flag&CHAR_DEL_EMAIL && ( - !stricmp(delcode, sd->email) || //email does not match or - ( - !stricmp("a@a.com", sd->email) && //it is default email and - !strcmp("", delcode) //user sent an empty email - ))) { - ShowInfo("" CL_RED "Char Deleted" CL_RESET " " CL_GREEN "(E-Mail)" CL_RESET ".\n"); - return true; +bool chclif_delchar_check(struct char_session_data *sd, uint32 char_id, std::string delcode) { + if (!sd->deletion_passcode.size()) { + ShowInfo("Character deletion failed, player's deletion code is never been set yet.\n"); + return false; } - // Birthdate (YYMMDD) - if (flag&CHAR_DEL_BIRTHDATE && ( - !strcmp(sd->birthdate+2, delcode) || // +2 to cut off the century - ( - !strcmp("",sd->birthdate) && // it is default birthdate and - !strcmp("",delcode) // user sent an empty birthdate - ))) { - ShowInfo("" CL_RED "Char Deleted" CL_RESET " " CL_GREEN "(Birthdate)" CL_RESET ".\n"); - return true; + + if (sd->deletion_passcode != delcode) { + ShowInfo("Character deletion failed. Player's deletion code is invalid.\n"); + return false; } - return false; + + ShowInfo("" CL_RED "Deleted" CL_RESET " char_id:%u.\n", char_id); + return true; } // CH: <0829>.W .L .6B int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) { FIFOSD_CHECK(12) { - char birthdate[8+1]; + char birthdate[6+1]; uint32 char_id; 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; + safestrncpy(birthdate, (char*)RFIFOP(fd, 6), sizeof(birthdate)); RFIFOSKIP(fd,12); // Only check for birthdate - if (!chclif_delchar_check(sd, birthdate, CHAR_DEL_BIRTHDATE)) { + if (!chclif_delchar_check(sd, char_id, birthdate)) { chclif_char_delete2_accept_ack(fd, char_id, 5); return 1; } @@ -988,19 +970,23 @@ void chclif_refuse_delchar(int fd, uint8 errCode){ WFIFOSET(fd,3); } +/** +* CH <0068>.W .L .40S +* CH <01FB>.W .L .50S +*/ int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd){ - if (cmd == 0x68) FIFOSD_CHECK(46) - else if (cmd == 0x1fb) FIFOSD_CHECK(56) - else return 0; + int offset = (cmd == 0x1fb) ? 10 : 0; + size_t len = 46 + offset; + FIFOSD_CHECK(len) { - char email[40]; + char delcode[49+1]; uint32 cid = RFIFOL(fd,2); ShowInfo(CL_RED "Request Char Deletion: " CL_GREEN "%u (%u)" CL_RESET "\n", sd->account_id, cid); - memcpy(email, RFIFOP(fd,6), 40); - RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56); + safestrncpy(delcode, (char*)RFIFOP(fd,6), 40 + offset); + RFIFOSKIP(fd, len); - if (!chclif_delchar_check(sd, email, charserv_config.char_config.char_del_option)) { + if (!chclif_delchar_check(sd, cid, delcode)) { chclif_refuse_delchar(fd,0); // 00 = Incorrect Email address return 1; } diff --git a/src/char/char_logif.cpp b/src/char/char_logif.cpp index 06c71366f5..9778d7aa13 100644 --- a/src/char/char_logif.cpp +++ b/src/char/char_logif.cpp @@ -4,7 +4,7 @@ #include "char_logif.hpp" #include -#include +#include #include "../common/showmsg.hpp" #include "../common/socket.hpp" @@ -332,11 +332,11 @@ int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd){ /** * Receive account data from login-server - * AH 0x2717 .L .40B .L .B .11B .5B .L .B .B .B + * AH 0x2717 .L .L .B .L .B .B .B .50B .11B .5B .50B **/ int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){ int u_fd; //user fd - if (RFIFOREST(fd) < 75) + if (RFIFOREST(fd) < 135) return 0; // find the authenticated session with this account id @@ -344,21 +344,22 @@ int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){ if( u_fd < 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); + sd->expiration_time = (time_t)RFIFOL(fd, 6); + sd->group_id = RFIFOB(fd, 10); + sd->char_slots = RFIFOB(fd, 11); if( sd->char_slots > MAX_CHARS ) { ShowError("Account '%d' `character_slots` column is higher than supported MAX_CHARS (%d), update MAX_CHARS in mmo.hpp! 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 = MIN_CHARS;/* cap to minimum */ - safestrncpy(sd->birthdate, RFIFOCP(fd,52), sizeof(sd->birthdate)); - safestrncpy(sd->pincode, RFIFOCP(fd,63), sizeof(sd->pincode)); - sd->pincode_change = (time_t)RFIFOL(fd,68); - sd->isvip = RFIFOB(fd,72); - sd->chars_vip = RFIFOB(fd,73); - sd->chars_billing = RFIFOB(fd,74); + sd->pincode_change = (time_t)RFIFOL(fd, 12); + sd->isvip = RFIFOB(fd, 16); + sd->chars_vip = RFIFOB(fd, 17); + sd->chars_billing = RFIFOB(fd, 18); + safestrncpy(sd->email, RFIFOCP(fd, 19), sizeof(sd->email)); + safestrncpy(sd->birthdate, RFIFOCP(fd, 69), sizeof(sd->birthdate)); + safestrncpy(sd->pincode, RFIFOCP(fd, 80), sizeof(sd->pincode)); + sd->deletion_passcode = RFIFOCP(fd, 85); ARR_FIND( 0, ARRAYLENGTH(map_server), server_id, map_server[server_id].fd > 0 && map_server[server_id].map[0] ); // continued from char_auth_ok... if( server_id == ARRAYLENGTH(map_server) || //server not online, bugreport:2359 @@ -374,7 +375,7 @@ int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){ #endif } } - RFIFOSKIP(fd,75); + RFIFOSKIP(fd, 135); return 1; } diff --git a/src/login/account.cpp b/src/login/account.cpp index 73b625ada3..a4bdc0b0db 100644 --- a/src/login/account.cpp +++ b/src/login/account.cpp @@ -2,10 +2,11 @@ // For more information, see LICENCE in the main folder #include "account.hpp" +#include "login.hpp" #include //min / max #include -#include +#include #include "../common/malloc.hpp" #include "../common/mmo.hpp" @@ -495,12 +496,13 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, uint32 // 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`" + ", IF(`sex` != 'S',%s,'') AS delcode" #ifdef VIP_ENABLE - "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`, `vip_time`, `old_group` FROM `%s` WHERE `account_id` = %d", -#else - "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", + ", `vip_time`, `old_group`" #endif - db->account_db, account_id ) + " FROM `%s` WHERE `account_id` = %d", + login_config.delcode_col.c_str(), db->account_db, account_id ) ) { Sql_ShowDebug(sql_handle); return false; @@ -528,12 +530,31 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, uint32 Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = (uint8) 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_GetData(sql_handle, 16, &data, NULL); acc->deletion_passcode = (data == NULL ? "" : data); #ifdef VIP_ENABLE - Sql_GetData(sql_handle, 16, &data, NULL); acc->vip_time = atol(data); - Sql_GetData(sql_handle, 17, &data, NULL); acc->old_group = atoi(data); + Sql_GetData(sql_handle, 17, &data, NULL); acc->vip_time = atol(data); + Sql_GetData(sql_handle, 18, &data, NULL); acc->old_group = atoi(data); #endif Sql_FreeResult(sql_handle); + if (acc->deletion_passcode.size()) { + // Make sure the delcode for birthdate from YYYY-MM-DD to YYMMDD + if (login_config.delcode_col == "`birthdate`") { + const std::string str = acc->deletion_passcode; + acc->deletion_passcode.clear(); + acc->deletion_passcode.append(str, 2, 1); + acc->deletion_passcode.append(str, 3, 1); + acc->deletion_passcode.append(str, 5, 1); + acc->deletion_passcode.append(str, 6, 1); + acc->deletion_passcode.append(str, 8, 1); + acc->deletion_passcode.append(str, 9, 1); + } + // Unset if email is default a@a.com + else if (login_config.delcode_col == "`email`" && acc->deletion_passcode == "a@a.com") { + acc->deletion_passcode = ""; + } + } + return true; } @@ -562,12 +583,16 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo 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`" #ifdef VIP_ENABLE - "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`, `vip_time`, `old_group` ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -#else - "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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + ",`vip_time`, `old_group`" #endif - db->account_db) + ")" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" +#ifdef VIP_ENABLE + ",?,?" +#endif + ")", 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)) @@ -596,13 +621,12 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo } else {// update account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, + 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`=?" #ifdef VIP_ENABLE - "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`=?, `vip_time`=?, `old_group`=? WHERE `account_id` = '%d'", -#else - "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'", + ",`vip_time`=?, `old_group`=?" #endif - db->account_db, acc->account_id) + " 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)) diff --git a/src/login/account.hpp b/src/login/account.hpp index d67ed752a8..b6a87b99cb 100644 --- a/src/login/account.hpp +++ b/src/login/account.hpp @@ -4,6 +4,8 @@ #ifndef _ACCOUNT_HPP_ #define _ACCOUNT_HPP_ +#include + #include "../common/cbasetypes.hpp" #include "../common/mmo.hpp" // ACCOUNT_REG2_NUM #include "../config/core.hpp" @@ -20,7 +22,7 @@ struct mmo_account { char userid[NAME_LENGTH]; char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords char sex; // gender (M/F/S) - char email[40]; // e-mail (by default: a@a.com) + char email[49+1]; // e-mail (by default: a@a.com) unsigned int group_id; // player group id uint8 char_slots; // this accounts maximum character slots (maximum is limited to MAX_CHARS define in char server) unsigned int state; // packet 0x006a value + 1 (0: compte OK) @@ -32,6 +34,7 @@ struct mmo_account { char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD) char pincode[PINCODE_LENGTH+1]; // pincode system time_t pincode_change; // (timestamp): last time of pincode change + std::string deletion_passcode; // Stores code for deleting character based on char_deletion_code config #ifdef VIP_ENABLE int old_group; time_t vip_time; diff --git a/src/login/login.cpp b/src/login/login.cpp index 8ff6ee3504..ead1221698 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -5,7 +5,6 @@ #include "login.hpp" #include -#include #include #include "../common/cli.hpp" @@ -241,6 +240,7 @@ int login_mmo_auth_new(const char* userid, const char* pass, const char sex, con safestrncpy(acc.pincode, "", sizeof(acc.pincode)); acc.pincode_change = 0; acc.char_slots = MIN_CHARS; + acc.deletion_passcode = ""; #ifdef VIP_ENABLE acc.vip_time = 0; acc.old_group = 0; @@ -638,6 +638,9 @@ bool login_config_read(const char* cfgName, bool normal) { login_config.char_per_account = MIN_CHARS; } } + else if (strcmpi(w1, "char_deletion_code") == 0) { + login_config.delcode_col = w2; + } #ifdef VIP_ENABLE else if(strcmpi(w1,"vip_group")==0) login_config.vip_sys.group = cap_value(atoi(w2),0,99); @@ -700,6 +703,12 @@ void login_set_defaults() { login_config.client_hash_check = 0; login_config.client_hash_nodes = NULL; login_config.char_per_account = MAX_CHARS - MAX_CHAR_VIP - MAX_CHAR_BILLING; +#if PACKETVER >= 20100803 + login_config.delcode_col = "`birthdate`"; +#else + login_config.delcode_col = "`email`"; +#endif + #ifdef VIP_ENABLE login_config.vip_sys.char_increase = MAX_CHAR_VIP; login_config.vip_sys.group = 5; @@ -866,6 +875,7 @@ int do_init(int argc, char** argv) { do_init_logincnslif(); + ShowInfo("Column used for character deletion is '" CL_WHITE "%s" CL_RESET "'\n", login_config.delcode_col.c_str()); 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"); diff --git a/src/login/login.hpp b/src/login/login.hpp index 4df76618d4..b8c1e3cca1 100644 --- a/src/login/login.hpp +++ b/src/login/login.hpp @@ -5,6 +5,7 @@ #define _LOGIN_HPP_ #include +#include #include "../common/cbasetypes.hpp" #include "../common/core.hpp" // CORE_ST_LAST @@ -97,6 +98,7 @@ struct Login_Config { char lanconf_name[256]; /// name of lan config file int char_per_account; /// number of characters an account can have + std::string delcode_col; #ifdef VIP_ENABLE struct { unsigned int group; /// VIP group ID diff --git a/src/login/loginchrif.cpp b/src/login/loginchrif.cpp index db207912fb..c84ec10882 100644 --- a/src/login/loginchrif.cpp +++ b/src/login/loginchrif.cpp @@ -4,7 +4,7 @@ #include "loginchrif.hpp" #include -#include +#include #include "../common/showmsg.hpp" //show notice #include "../common/socket.hpp" //wfifo session @@ -152,50 +152,38 @@ int logchrif_parse_ackusercount(int fd, int id){ */ int logchrif_send_accdata(int fd, uint32 aid) { struct mmo_account acc; - time_t expiration_time = 0; - char email[40] = ""; - int group_id = 0; - char birthdate[10+1] = ""; - char pincode[PINCODE_LENGTH+1]; char isvip = false; uint8 char_slots = MIN_CHARS, char_vip = 0, char_billing = 0; AccountDB* accounts = login_get_accounts_db(); - memset(pincode,0,PINCODE_LENGTH+1); if( !accounts->load_num(accounts, &acc, aid) ) return -1; - else { - safestrncpy(email, acc.email, sizeof(email)); - expiration_time = acc.expiration_time; - group_id = acc.group_id; - safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); - safestrncpy(pincode, acc.pincode, sizeof(pincode)); #ifdef VIP_ENABLE - char_vip = login_config.vip_sys.char_increase; - if( acc.vip_time > time(NULL) ) { - isvip = true; - char_slots = login_config.char_per_account + char_vip; - } else - char_slots = login_config.char_per_account; - char_billing = MAX_CHAR_BILLING; //TODO create a config for this + char_vip = login_config.vip_sys.char_increase; + if( acc.vip_time > time(NULL) ) { + isvip = true; + char_slots = login_config.char_per_account + char_vip; + } else + char_slots = login_config.char_per_account; + char_billing = MAX_CHAR_BILLING; //TODO create a config for this #endif - } - WFIFOHEAD(fd,75); - WFIFOW(fd,0) = 0x2717; - WFIFOL(fd,2) = aid; - safestrncpy(WFIFOCP(fd,6), email, 40); - WFIFOL(fd,46) = (uint32)expiration_time; - WFIFOB(fd,50) = (unsigned char)group_id; - WFIFOB(fd,51) = char_slots; - safestrncpy(WFIFOCP(fd,52), birthdate, 10+1); - safestrncpy(WFIFOCP(fd,63), pincode, 4+1 ); - WFIFOL(fd,68) = (uint32)acc.pincode_change; - WFIFOB(fd,72) = isvip; - WFIFOB(fd,73) = char_vip; - WFIFOB(fd,74) = char_billing; - WFIFOSET(fd,75); + WFIFOHEAD(fd, 135); + WFIFOW(fd, 0) = 0x2717; + WFIFOL(fd, 2) = aid; + WFIFOL(fd, 6) = (uint32)acc.expiration_time; + WFIFOB(fd, 10) = (unsigned char)acc.group_id; + WFIFOB(fd, 11) = char_slots; + WFIFOL(fd, 12) = (uint32)acc.pincode_change; + WFIFOB(fd, 16) = isvip; + WFIFOB(fd, 17) = char_vip; + WFIFOB(fd, 18) = char_billing; + safestrncpy(WFIFOCP(fd, 19), acc.email, 50); + safestrncpy(WFIFOCP(fd, 69), acc.birthdate, 10 + 1); + safestrncpy(WFIFOCP(fd, 80), acc.pincode, 4 + 1); + safestrncpy(WFIFOCP(fd, 85), acc.deletion_passcode.c_str(), 50/*DELCODE_LENGTH*/); + WFIFOSET(fd, 135); return 1; }