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
This commit is contained in:
Cydh Ramdh 2018-07-02 17:28:58 +07:00
parent 3faf700443
commit 4b434fa669
14 changed files with 148 additions and 148 deletions

View File

@ -170,18 +170,6 @@ char_del_level: 0
// NOTE: Requires client 2010-08-03aragexeRE or newer. // NOTE: Requires client 2010-08-03aragexeRE or newer.
char_del_delay: 86400 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 // Restrict character deletion as long as he is still in a party or guild
// 0: No restriction is applied // 0: No restriction is applied
// 1: Character cannot be deleted as long as he remains in a party // 1: Character cannot be deleted as long as he remains in a party

View File

@ -110,6 +110,18 @@ start_limited_time: -1
// NOTE: Will not work with clients that use <passwordencrypt> // NOTE: Will not work with clients that use <passwordencrypt>
use_MD5_passwords: no 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 features
ipban_enable: yes ipban_enable: yes
// Dynamic password failure ipban system // Dynamic password failure ipban system

View File

@ -89,22 +89,23 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket.
0x2717 0x2717
Type: AH Type: AH
Structure: <cmd>.W <aid>.L <email>.40B <expiration_time>.L <group_id>.B <char_slots>.B <birthdate>.11B <pincode>.5B <pincode_change>.L <isvip>.B <char_vip>.B <MAX_CHAR_BILLING>.B Structure: <cmd>.W <aid>.L <expiration_time>.L <group_id>.B <char_slots>.B <pincode_change>.L <isvip>.B <char_vip>.B <MAX_CHAR_BILLING>.B <email>.50S <birthdate>.11S <pincode>.5S <deletion_code>.50S
index: 0,2,6,46,50,51,52,63,68,72,73,74 index: 0,2,6,10,11,12,16,17,18,19,69,80,85
len: 75 len: 75
parameter: parameter:
- cmd: packet identification (0x2717) - cmd: packet identification (0x2717)
- aid: account identification - aid: account identification
- email: email of aid
- expiration_time: unknow @FIXME - expiration_time: unknow @FIXME
- group_id: the group the aid belong too - group_id: the group the aid belong too
- char_slots: number of slot available the account have (will be displayed on client) - 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 - pincode_change: new pincode of aid
- isvip: if this aid is currently vip or not - 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) - 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 - 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: desc:
- Request account data - Request account data

View File

@ -705,7 +705,7 @@ CREATE TABLE IF NOT EXISTS `login` (
`userid` varchar(23) NOT NULL default '', `userid` varchar(23) NOT NULL default '',
`user_pass` varchar(32) NOT NULL default '', `user_pass` varchar(32) NOT NULL default '',
`sex` enum('M','F','S') NOT NULL default 'M', `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', `group_id` tinyint(3) NOT NULL default '0',
`state` int(11) unsigned NOT NULL default '0', `state` int(11) unsigned NOT NULL default '0',
`unban_time` int(11) unsigned NOT NULL default '0', `unban_time` int(11) unsigned NOT NULL default '0',

View File

@ -0,0 +1 @@
ALTER TABLE `login` MODIFY COLUMN `email` VARCHAR(49) NULL DEFAULT '';

View File

@ -7,7 +7,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string>
#include <time.h> #include <time.h>
#include "../common/cbasetypes.hpp" #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_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_level = 0; //From which level u can delete character [Lupus]
charserv_config.char_config.char_del_delay = 86400; 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.char_config.char_del_restriction = CHAR_DEL_RESTRICT_ALL;
// charserv_config.userid[24]; // 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); charserv_config.char_config.char_del_level = atoi(w2);
} else if (strcmpi(w1, "char_del_delay") == 0) { } else if (strcmpi(w1, "char_del_delay") == 0) {
charserv_config.char_config.char_del_delay = atoi(w2); 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) { } else if (strcmpi(w1, "char_del_restriction") == 0) {
charserv_config.char_config.char_del_restriction = atoi(w2); charserv_config.char_config.char_del_restriction = atoi(w2);
} else if (strcmpi(w1, "char_rename_party") == 0) { } 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. * Checks for values out of range.
*/ */
void char_config_adjust() { 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
} }
/* /*

View File

@ -4,6 +4,8 @@
#ifndef _CHAR_HPP_ #ifndef _CHAR_HPP_
#define _CHAR_HPP_ #define _CHAR_HPP_
#include <string>
#include "../common/core.hpp" // CORE_ST_LAST #include "../common/core.hpp" // CORE_ST_LAST
#include "../common/mmo.hpp" #include "../common/mmo.hpp"
#include "../common/msg_conf.hpp" #include "../common/msg_conf.hpp"
@ -22,11 +24,6 @@ enum E_CHARSERVER_ST {
CHARSERVER_ST_LAST CHARSERVER_ST_LAST
}; };
enum e_char_delete {
CHAR_DEL_EMAIL = 1,
CHAR_DEL_BIRTHDATE
};
enum e_char_delete_restriction { enum e_char_delete_restriction {
CHAR_DEL_RESTRICT_PARTY = 1, CHAR_DEL_RESTRICT_PARTY = 1,
CHAR_DEL_RESTRICT_GUILD, 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 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] 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_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) 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_party; // Character renaming in a party
bool char_rename_guild; // Character renaming in a guild 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 bool auth; // whether the session is authed or not
uint32 account_id, login_id1, login_id2, sex; uint32 account_id, login_id1, login_id2, sex;
int found_char[MAX_CHARS]; // ids of chars on this account 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) time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
int group_id; // permission int group_id; // permission
uint8 char_slots; // total number of characters that can be created 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]; time_t unban_time[MAX_CHARS];
int charblock_timer; int charblock_timer;
uint8 flag; // &1 - Retrieving guild bound items uint8 flag; // &1 - Retrieving guild bound items
std::string deletion_passcode;
}; };

View File

@ -4,7 +4,7 @@
#include "char_clif.hpp" #include "char_clif.hpp"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string>
#include "../common/malloc.hpp" #include "../common/malloc.hpp"
#include "../common/mapindex.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 * Check char deletion code
* @param sd * @param sd
* @param delcode E-mail or birthdate * @param char_id Requested Char ID
* @param flag Delete flag * @param delcode Deletion code from cleint
* @return true:Success, false:Failure * @return true:Success, false:Failure
**/ **/
bool chclif_delchar_check(struct char_session_data *sd, char *delcode, uint8 flag) { bool chclif_delchar_check(struct char_session_data *sd, uint32 char_id, std::string delcode) {
// E-Mail check if (!sd->deletion_passcode.size()) {
if (flag&CHAR_DEL_EMAIL && ( ShowInfo("Character deletion failed, player's deletion code is never been set yet.\n");
!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;
}
// 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;
}
return false; return false;
}
if (sd->deletion_passcode != delcode) {
ShowInfo("Character deletion failed. Player's deletion code is invalid.\n");
return false;
}
ShowInfo("" CL_RED "Deleted" CL_RESET " char_id:%u.\n", char_id);
return true;
} }
// CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B // CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) { int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) {
FIFOSD_CHECK(12) FIFOSD_CHECK(12)
{ {
char birthdate[8+1]; char birthdate[6+1];
uint32 char_id; uint32 char_id;
char_id = RFIFOL(fd,2); char_id = RFIFOL(fd,2);
ShowInfo(CL_RED "Request Char Deletion: " CL_GREEN "%d (%d)" CL_RESET "\n", sd->account_id, char_id); ShowInfo(CL_RED "Request Char Deletion: " CL_GREEN "%d (%d)" CL_RESET "\n", sd->account_id, char_id);
// construct "YY-MM-DD" safestrncpy(birthdate, (char*)RFIFOP(fd, 6), sizeof(birthdate));
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;
RFIFOSKIP(fd,12); RFIFOSKIP(fd,12);
// Only check for birthdate // 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); chclif_char_delete2_accept_ack(fd, char_id, 5);
return 1; return 1;
} }
@ -988,19 +970,23 @@ void chclif_refuse_delchar(int fd, uint8 errCode){
WFIFOSET(fd,3); WFIFOSET(fd,3);
} }
/**
* CH <0068>.W <char_id>.L <email>.40S
* CH <01FB>.W <char_id>.L <email>.50S
*/
int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd){ int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd){
if (cmd == 0x68) FIFOSD_CHECK(46) int offset = (cmd == 0x1fb) ? 10 : 0;
else if (cmd == 0x1fb) FIFOSD_CHECK(56) size_t len = 46 + offset;
else return 0; FIFOSD_CHECK(len)
{ {
char email[40]; char delcode[49+1];
uint32 cid = RFIFOL(fd,2); uint32 cid = RFIFOL(fd,2);
ShowInfo(CL_RED "Request Char Deletion: " CL_GREEN "%u (%u)" CL_RESET "\n", sd->account_id, cid); ShowInfo(CL_RED "Request Char Deletion: " CL_GREEN "%u (%u)" CL_RESET "\n", sd->account_id, cid);
memcpy(email, RFIFOP(fd,6), 40); safestrncpy(delcode, (char*)RFIFOP(fd,6), 40 + offset);
RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56); 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 chclif_refuse_delchar(fd,0); // 00 = Incorrect Email address
return 1; return 1;
} }

View File

@ -4,7 +4,7 @@
#include "char_logif.hpp" #include "char_logif.hpp"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string>
#include "../common/showmsg.hpp" #include "../common/showmsg.hpp"
#include "../common/socket.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 * Receive account data from login-server
* AH 0x2717 <aid>.L <email>.40B <expiration_time>.L <group_id>.B <birthdate>.11B <pincode>.5B <pincode_change>.L <isvip>.B <char_vip>.B <char_billing>.B * AH 0x2717 <aid>.L <expiration_time>.L <group_id>.B <pincode_change>.L <isvip>.B <char_vip>.B <char_billing>.B <email>.50B <birthdate>.11B <pincode>.5B <deletion_passcode>.50B
**/ **/
int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){ int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){
int u_fd; //user fd int u_fd; //user fd
if (RFIFOREST(fd) < 75) if (RFIFOREST(fd) < 135)
return 0; return 0;
// find the authenticated session with this account id // 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 ) if( u_fd < fd_max )
{ {
int server_id; int server_id;
memcpy(sd->email, RFIFOP(fd,6), 40); sd->expiration_time = (time_t)RFIFOL(fd, 6);
sd->expiration_time = (time_t)RFIFOL(fd,46); sd->group_id = RFIFOB(fd, 10);
sd->group_id = RFIFOB(fd,50); sd->char_slots = RFIFOB(fd, 11);
sd->char_slots = RFIFOB(fd,51);
if( sd->char_slots > MAX_CHARS ) { 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); 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 */ sd->char_slots = MAX_CHARS;/* cap to maximum */
} else if ( !sd->char_slots )/* no value aka 0 in sql */ } else if ( !sd->char_slots )/* no value aka 0 in sql */
sd->char_slots = MIN_CHARS;/* cap to minimum */ sd->char_slots = MIN_CHARS;/* cap to minimum */
safestrncpy(sd->birthdate, RFIFOCP(fd,52), sizeof(sd->birthdate)); sd->pincode_change = (time_t)RFIFOL(fd, 12);
safestrncpy(sd->pincode, RFIFOCP(fd,63), sizeof(sd->pincode)); sd->isvip = RFIFOB(fd, 16);
sd->pincode_change = (time_t)RFIFOL(fd,68); sd->chars_vip = RFIFOB(fd, 17);
sd->isvip = RFIFOB(fd,72); sd->chars_billing = RFIFOB(fd, 18);
sd->chars_vip = RFIFOB(fd,73); safestrncpy(sd->email, RFIFOCP(fd, 19), sizeof(sd->email));
sd->chars_billing = RFIFOB(fd,74); 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] ); 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... // continued from char_auth_ok...
if( server_id == ARRAYLENGTH(map_server) || //server not online, bugreport:2359 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 #endif
} }
} }
RFIFOSKIP(fd,75); RFIFOSKIP(fd, 135);
return 1; return 1;
} }

View File

@ -2,10 +2,11 @@
// For more information, see LICENCE in the main folder // For more information, see LICENCE in the main folder
#include "account.hpp" #include "account.hpp"
#include "login.hpp"
#include <algorithm> //min / max #include <algorithm> //min / max
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string>
#include "../common/malloc.hpp" #include "../common/malloc.hpp"
#include "../common/mmo.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 // retrieve login entry for the specified account
if( SQL_ERROR == Sql_Query(sql_handle, 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 #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", ", `vip_time`, `old_group`"
#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",
#endif #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); Sql_ShowDebug(sql_handle);
return false; 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, 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, 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, 15, &data, NULL); acc->pincode_change = atol(data);
Sql_GetData(sql_handle, 16, &data, NULL); acc->deletion_passcode = (data == NULL ? "" : data);
#ifdef VIP_ENABLE #ifdef VIP_ENABLE
Sql_GetData(sql_handle, 16, &data, NULL); acc->vip_time = atol(data); Sql_GetData(sql_handle, 17, &data, NULL); acc->vip_time = atol(data);
Sql_GetData(sql_handle, 17, &data, NULL); acc->old_group = atoi(data); Sql_GetData(sql_handle, 18, &data, NULL); acc->old_group = atoi(data);
#endif #endif
Sql_FreeResult(sql_handle); 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; return true;
} }
@ -562,12 +583,16 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
if( is_new ) if( is_new )
{// insert into account table {// insert into account table
if( SQL_SUCCESS != SqlStmt_Prepare(stmt, 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 #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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ",`vip_time`, `old_group`"
#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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
#endif #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, 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, 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, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass))
@ -597,12 +622,11 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
else else
{// update account table {// 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 #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'", ",`vip_time`=?, `old_group`=?"
#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'",
#endif #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, 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, 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, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex))

View File

@ -4,6 +4,8 @@
#ifndef _ACCOUNT_HPP_ #ifndef _ACCOUNT_HPP_
#define _ACCOUNT_HPP_ #define _ACCOUNT_HPP_
#include <string>
#include "../common/cbasetypes.hpp" #include "../common/cbasetypes.hpp"
#include "../common/mmo.hpp" // ACCOUNT_REG2_NUM #include "../common/mmo.hpp" // ACCOUNT_REG2_NUM
#include "../config/core.hpp" #include "../config/core.hpp"
@ -20,7 +22,7 @@ struct mmo_account {
char userid[NAME_LENGTH]; char userid[NAME_LENGTH];
char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords
char sex; // gender (M/F/S) 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 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) 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) 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 birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD)
char pincode[PINCODE_LENGTH+1]; // pincode system char pincode[PINCODE_LENGTH+1]; // pincode system
time_t pincode_change; // (timestamp): last time of pincode change 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 #ifdef VIP_ENABLE
int old_group; int old_group;
time_t vip_time; time_t vip_time;

View File

@ -5,7 +5,6 @@
#include "login.hpp" #include "login.hpp"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <string> #include <string>
#include "../common/cli.hpp" #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)); safestrncpy(acc.pincode, "", sizeof(acc.pincode));
acc.pincode_change = 0; acc.pincode_change = 0;
acc.char_slots = MIN_CHARS; acc.char_slots = MIN_CHARS;
acc.deletion_passcode = "";
#ifdef VIP_ENABLE #ifdef VIP_ENABLE
acc.vip_time = 0; acc.vip_time = 0;
acc.old_group = 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; login_config.char_per_account = MIN_CHARS;
} }
} }
else if (strcmpi(w1, "char_deletion_code") == 0) {
login_config.delcode_col = w2;
}
#ifdef VIP_ENABLE #ifdef VIP_ENABLE
else if(strcmpi(w1,"vip_group")==0) else if(strcmpi(w1,"vip_group")==0)
login_config.vip_sys.group = cap_value(atoi(w2),0,99); 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_check = 0;
login_config.client_hash_nodes = NULL; login_config.client_hash_nodes = NULL;
login_config.char_per_account = MAX_CHARS - MAX_CHAR_VIP - MAX_CHAR_BILLING; 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 #ifdef VIP_ENABLE
login_config.vip_sys.char_increase = MAX_CHAR_VIP; login_config.vip_sys.char_increase = MAX_CHAR_VIP;
login_config.vip_sys.group = 5; login_config.vip_sys.group = 5;
@ -866,6 +875,7 @@ int do_init(int argc, char** argv) {
do_init_logincnslif(); 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); 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"); login_log(0, "login server", 100, "login server started");

View File

@ -5,6 +5,7 @@
#define _LOGIN_HPP_ #define _LOGIN_HPP_
#include <memory> #include <memory>
#include <string>
#include "../common/cbasetypes.hpp" #include "../common/cbasetypes.hpp"
#include "../common/core.hpp" // CORE_ST_LAST #include "../common/core.hpp" // CORE_ST_LAST
@ -97,6 +98,7 @@ struct Login_Config {
char lanconf_name[256]; /// name of lan config file char lanconf_name[256]; /// name of lan config file
int char_per_account; /// number of characters an account can have int char_per_account; /// number of characters an account can have
std::string delcode_col;
#ifdef VIP_ENABLE #ifdef VIP_ENABLE
struct { struct {
unsigned int group; /// VIP group ID unsigned int group; /// VIP group ID

View File

@ -4,7 +4,7 @@
#include "loginchrif.hpp" #include "loginchrif.hpp"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string>
#include "../common/showmsg.hpp" //show notice #include "../common/showmsg.hpp" //show notice
#include "../common/socket.hpp" //wfifo session #include "../common/socket.hpp" //wfifo session
@ -152,25 +152,13 @@ int logchrif_parse_ackusercount(int fd, int id){
*/ */
int logchrif_send_accdata(int fd, uint32 aid) { int logchrif_send_accdata(int fd, uint32 aid) {
struct mmo_account acc; 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; char isvip = false;
uint8 char_slots = MIN_CHARS, char_vip = 0, char_billing = 0; uint8 char_slots = MIN_CHARS, char_vip = 0, char_billing = 0;
AccountDB* accounts = login_get_accounts_db(); AccountDB* accounts = login_get_accounts_db();
memset(pincode,0,PINCODE_LENGTH+1);
if( !accounts->load_num(accounts, &acc, aid) ) if( !accounts->load_num(accounts, &acc, aid) )
return -1; 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 #ifdef VIP_ENABLE
char_vip = login_config.vip_sys.char_increase; char_vip = login_config.vip_sys.char_increase;
if( acc.vip_time > time(NULL) ) { if( acc.vip_time > time(NULL) ) {
@ -180,22 +168,22 @@ int logchrif_send_accdata(int fd, uint32 aid) {
char_slots = login_config.char_per_account; char_slots = login_config.char_per_account;
char_billing = MAX_CHAR_BILLING; //TODO create a config for this char_billing = MAX_CHAR_BILLING; //TODO create a config for this
#endif #endif
}
WFIFOHEAD(fd,75); WFIFOHEAD(fd, 135);
WFIFOW(fd,0) = 0x2717; WFIFOW(fd, 0) = 0x2717;
WFIFOL(fd,2) = aid; WFIFOL(fd, 2) = aid;
safestrncpy(WFIFOCP(fd,6), email, 40); WFIFOL(fd, 6) = (uint32)acc.expiration_time;
WFIFOL(fd,46) = (uint32)expiration_time; WFIFOB(fd, 10) = (unsigned char)acc.group_id;
WFIFOB(fd,50) = (unsigned char)group_id; WFIFOB(fd, 11) = char_slots;
WFIFOB(fd,51) = char_slots; WFIFOL(fd, 12) = (uint32)acc.pincode_change;
safestrncpy(WFIFOCP(fd,52), birthdate, 10+1); WFIFOB(fd, 16) = isvip;
safestrncpy(WFIFOCP(fd,63), pincode, 4+1 ); WFIFOB(fd, 17) = char_vip;
WFIFOL(fd,68) = (uint32)acc.pincode_change; WFIFOB(fd, 18) = char_billing;
WFIFOB(fd,72) = isvip; safestrncpy(WFIFOCP(fd, 19), acc.email, 50);
WFIFOB(fd,73) = char_vip; safestrncpy(WFIFOCP(fd, 69), acc.birthdate, 10 + 1);
WFIFOB(fd,74) = char_billing; safestrncpy(WFIFOCP(fd, 80), acc.pincode, 4 + 1);
WFIFOSET(fd,75); safestrncpy(WFIFOCP(fd, 85), acc.deletion_passcode.c_str(), 50/*DELCODE_LENGTH*/);
WFIFOSET(fd, 135);
return 1; return 1;
} }