Cleaned up character deletion code (#2296)

* Fixes #2271
Thanks to @Tokeiburu
This commit is contained in:
Lemongrass3110 2017-08-05 00:46:17 +02:00 committed by Aleos
parent de3f924afc
commit bbd42e7f12
3 changed files with 95 additions and 81 deletions

View File

@ -1518,22 +1518,34 @@ int char_divorce_char_sql(int partner_id1, int partner_id2){
/* Returns 0 if successful
* Returns < 0 for error
*/
int char_delete_char_sql(uint32 char_id){
enum e_char_del_response char_delete(struct char_session_data* sd, uint32 char_id){
char name[NAME_LENGTH];
char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped.
uint32 account_id;
int party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id, elemental_id;
time_t delete_date;
char *data;
size_t len;
int i, k;
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))
ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id);
// Such a character does not exist in the account
if (i == MAX_CHARS) {
ShowInfo("Char deletion aborted: %s, Account ID: %u, Character ID: %u\n", name, sd->account_id, char_id);
return CHAR_DELETE_NOTFOUND;
}
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`,`delete_date` FROM `%s` WHERE `account_id`='%u' AND `char_id`='%u'", schema_config.char_db, sd->account_id, char_id)){
Sql_ShowDebug(sql_handle);
return CHAR_DELETE_DATABASE;
}
if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
{
ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n");
ShowInfo("Char deletion aborted: %s, Account ID: %u, Character ID: %u\n", name, sd->account_id, char_id);
Sql_FreeResult(sql_handle);
return -1;
return CHAR_DELETE_NOTFOUND;
}
Sql_GetData(sql_handle, 0, &data, &len); safestrncpy(name, data, NAME_LENGTH);
@ -1546,29 +1558,34 @@ int char_delete_char_sql(uint32 char_id){
Sql_GetData(sql_handle, 7, &data, NULL); father_id = atoi(data);
Sql_GetData(sql_handle, 8, &data, NULL); mother_id = atoi(data);
Sql_GetData(sql_handle, 9, &data, NULL); elemental_id = atoi(data);
Sql_GetData(sql_handle,10, &data, NULL); delete_date = strtoul(data, NULL, 10);
Sql_EscapeStringLen(sql_handle, esc_name, name, zmin(len, NAME_LENGTH));
Sql_FreeResult(sql_handle);
//check for config char del condition [Lupus]
// TODO: Move this out to packet processing (0x68/0x1fb).
if( ( charserv_config.char_config.char_del_level > 0 && base_level >= charserv_config.char_config.char_del_level )
|| ( charserv_config.char_config.char_del_level < 0 && base_level <= -charserv_config.char_config.char_del_level )
) {
ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level);
return -1;
return CHAR_DELETE_BASELEVEL;
}
if (charserv_config.char_config.char_del_restriction&CHAR_DEL_RESTRICT_GUILD && guild_id) // character is in guild
{
ShowInfo("Char deletion aborted: %s, Guild ID: %i\n", name, guild_id);
return -1;
return CHAR_DELETE_GUILD;
}
if (charserv_config.char_config.char_del_restriction&CHAR_DEL_RESTRICT_PARTY && party_id) // character is in party
{
ShowInfo("Char deletion aborted: %s, Party ID: %i\n", name, party_id);
return -1;
return CHAR_DELETE_PARTY;
}
if( charserv_config.char_config.char_del_delay > 0 && ( !delete_date || delete_date > time(NULL) ) ){ // not queued or delay not yet passed
ShowInfo("Char deletion aborted: %s, Time was not set or has not been reached ye\n", name );
return CHAR_DELETE_TIME;
}
/* Divorce [Wizputer] */
@ -1582,7 +1599,7 @@ int char_delete_char_sql(uint32 char_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')", schema_config.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;
@ -1699,7 +1716,14 @@ int char_delete_char_sql(uint32 char_id){
mapif_parse_BreakGuild(0,guild_id);
else if( guild_id )
inter_guild_leave(guild_id, account_id, char_id);// Leave your guild.
return 0;
// 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;
return CHAR_DELETE_OK;
}
/**

View File

@ -38,6 +38,16 @@ enum e_char_delete_restriction {
CHAR_DEL_RESTRICT_ALL
};
enum e_char_del_response {
CHAR_DELETE_OK = 0,
CHAR_DELETE_DATABASE,
CHAR_DELETE_NOTFOUND,
CHAR_DELETE_BASELEVEL,
CHAR_DELETE_GUILD,
CHAR_DELETE_PARTY,
CHAR_DELETE_TIME,
};
struct Schema_Config {
int db_use_sqldbs;
char db_path[1024];
@ -272,7 +282,7 @@ int char_mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p);
int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p);
int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_everything);
int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf);
int char_delete_char_sql(uint32 char_id);
enum e_char_del_response char_delete(struct char_session_data* sd, uint32 char_id);
int char_rename_char_sql(struct char_session_data *sd, uint32 char_id);
int char_divorce_char_sql(int partner_id1, int partner_id2);
int char_memitemdata_to_sql(const struct item items[], int max, int id, enum storage_type tableswitch, uint8 stor_id);

View File

@ -437,8 +437,10 @@ void chclif_char_delete2_ack(int fd, uint32 char_id, uint32 result, time_t delet
/// 3 (0x719): A database error occurred.
/// 4 (0x71d): Deleting not yet possible time.
/// 5 (0x71e): Date of birth do not match.
/// 6 Name does not match.
/// 7 Character Deletion has failed because you have entered an incorrect e-mail address.
/// Any (0x718): An unknown error has occurred.
/// HC: <082a>.W <char id>.L <Msg:0-5>.L
/// HC: <082a>.W <char id>.L <Msg>.L
void chclif_char_delete2_accept_ack(int fd, uint32 char_id, uint32 result) {
#if PACKETVER >= 20130000
if(result == 1 ){
@ -563,10 +565,7 @@ int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) {
FIFOSD_CHECK(12)
{
char birthdate[8+1];
uint32 char_id, i, k;
unsigned int base_level;
char* data;
time_t delete_date;
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);
@ -583,54 +582,36 @@ int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) {
birthdate[8] = 0;
RFIFOSKIP(fd,12);
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
if( i == MAX_CHARS )
{// character not found
chclif_char_delete2_accept_ack(fd, char_id, 3);
return 1;
}
if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", schema_config.char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
{// data error
Sql_ShowDebug(sql_handle);
chclif_char_delete2_accept_ack(fd, char_id, 3);
return 1;
}
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
chclif_char_delete2_accept_ack(fd, char_id, 4);
return 1;
}
if (!chclif_delchar_check(sd, birthdate, CHAR_DEL_BIRTHDATE)) { // Only check for birthdate
// Only check for birthdate
if (!chclif_delchar_check(sd, birthdate, CHAR_DEL_BIRTHDATE)) {
chclif_char_delete2_accept_ack(fd, char_id, 5);
return 1;
}
if( ( charserv_config.char_config.char_del_level > 0 && base_level >= (unsigned int)charserv_config.char_config.char_del_level )
|| ( charserv_config.char_config.char_del_level < 0 && base_level <= (unsigned int)(-charserv_config.char_config.char_del_level) ) )
{// character level config restriction
chclif_char_delete2_accept_ack(fd, char_id, 2);
return 1;
switch( char_delete(sd,char_id) ){
// success
case CHAR_DELETE_OK:
chclif_char_delete2_accept_ack(fd, char_id, 1);
break;
// data error
case CHAR_DELETE_DATABASE:
// character not found
case CHAR_DELETE_NOTFOUND:
chclif_char_delete2_accept_ack(fd, char_id, 3);
break;
// in a party
case CHAR_DELETE_PARTY:
// in a guild
case CHAR_DELETE_GUILD:
// character level config restriction
case CHAR_DELETE_BASELEVEL:
chclif_char_delete2_accept_ack(fd, char_id, 2);
break;
// not queued or delay not yet passed
case CHAR_DELETE_TIME:
chclif_char_delete2_accept_ack(fd, char_id, 4);
break;
}
// success
if( char_delete_char_sql(char_id) < 0 ){
chclif_char_delete2_accept_ack(fd, char_id, 3);
return 1;
}
// 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;
chclif_char_delete2_accept_ack(fd, char_id, 1);
}
return 1;
}
@ -993,7 +974,9 @@ int chclif_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
* 0x70 <ErrorCode>B HC_REFUSE_DELETECHAR
* @param fd
* @param ErrorCode
* 00 = Incorrect Email address
* 00 = Incorrect Email address
* 01 = Invalid Slot
* 02 = In a party or guild
*/
void chclif_refuse_delchar(int fd, uint8 errCode){
WFIFOHEAD(fd,3);
@ -1008,10 +991,9 @@ int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd){
else return 0;
{
char email[40];
int i, ch;
int cid = RFIFOL(fd,2);
uint32 cid = RFIFOL(fd,2);
ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"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);
RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
@ -1020,26 +1002,24 @@ int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd){
return 1;
}
// 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
chclif_refuse_delchar(fd,0);
return 1;
}
// 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(char_delete_char_sql(cid)<0){
//can't delete the char
//either SQL error or can't delete by some CONFIG conditions
//del fail
chclif_refuse_delchar(fd,0);
return 1;
switch( char_delete(sd,cid) ){
case CHAR_DELETE_OK:
break;
case CHAR_DELETE_DATABASE:
case CHAR_DELETE_BASELEVEL:
case CHAR_DELETE_TIME:
chclif_refuse_delchar(fd, 0);
return 1;
case CHAR_DELETE_NOTFOUND:
chclif_refuse_delchar(fd, 1);
return 1;
case CHAR_DELETE_GUILD:
case CHAR_DELETE_PARTY:
chclif_refuse_delchar(fd, 2);
return 1;
}
/* Char successfully deleted.*/
WFIFOHEAD(fd,2);
WFIFOW(fd,0) = 0x6f;