Procházet zdrojové kódy

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

Cydh Ramdh před 7 roky
rodič
revize
4b434fa669

+ 0 - 12
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

+ 12 - 0
conf/login_athena.conf

@@ -110,6 +110,18 @@ start_limited_time: -1
 // NOTE: Will not work with clients that use <passwordencrypt>
 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

+ 6 - 5
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: <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
-	index: 0,2,6,46,50,51,52,63,68,72,73,74
+	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,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
 

+ 1 - 1
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',

+ 1 - 0
sql-files/upgrades/email_extends.sql

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

+ 1 - 14
src/char/char.cpp

@@ -7,7 +7,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <string>
 #include <time.h>
 
 #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
 }
 
 /*

+ 4 - 7
src/char/char.hpp

@@ -4,6 +4,8 @@
 #ifndef _CHAR_HPP_
 #define _CHAR_HPP_
 
+#include <string>
+
 #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;
 };
 
 

+ 28 - 42
src/char/char_clif.cpp

@@ -4,7 +4,7 @@
 #include "char_clif.hpp"
 
 #include <stdlib.h>
-#include <string.h>
+#include <string>
 
 #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 <char id>.L <birth date:YYMMDD>.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 <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){
-	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;
 		}

+ 15 - 14
src/char/char_logif.cpp

@@ -4,7 +4,7 @@
 #include "char_logif.hpp"
 
 #include <stdlib.h>
-#include <string.h>
+#include <string>
 
 #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 <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 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;
 }
 

+ 40 - 16
src/login/account.cpp

@@ -2,10 +2,11 @@
 // For more information, see LICENCE in the main folder
 
 #include "account.hpp"
+#include "login.hpp"
 
 #include <algorithm> //min / max
 #include <stdlib.h>
-#include <string.h>
+#include <string>
 
 #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))

+ 4 - 1
src/login/account.hpp

@@ -4,6 +4,8 @@
 #ifndef _ACCOUNT_HPP_
 #define _ACCOUNT_HPP_
 
+#include <string>
+
 #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;

+ 11 - 1
src/login/login.cpp

@@ -5,7 +5,6 @@
 #include "login.hpp"
 
 #include <stdlib.h>
-#include <string.h>
 #include <string>
 
 #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");
 

+ 2 - 0
src/login/login.hpp

@@ -5,6 +5,7 @@
 #define _LOGIN_HPP_
 
 #include <memory>
+#include <string>
 
 #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

+ 23 - 35
src/login/loginchrif.cpp

@@ -4,7 +4,7 @@
 #include "loginchrif.hpp"
 
 #include <stdlib.h>
-#include <string.h>
+#include <string>
 
 #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;
 }