From bbd42e7f12ee2b06807feed62d25f5a94ce5aa09 Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Sat, 5 Aug 2017 00:46:17 +0200 Subject: [PATCH] Cleaned up character deletion code (#2296) * Fixes #2271 Thanks to @Tokeiburu --- src/char/char.cpp | 44 ++++++++++++---- src/char/char.h | 12 ++++- src/char/char_clif.c | 120 ++++++++++++++++++------------------------- 3 files changed, 95 insertions(+), 81 deletions(-) diff --git a/src/char/char.cpp b/src/char/char.cpp index 2ff09d9fc5..688df3da43 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -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; } /** diff --git a/src/char/char.h b/src/char/char.h index 0163898ea7..9aabae96f2 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -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); diff --git a/src/char/char_clif.c b/src/char/char_clif.c index 83c21ff2f1..66cb2262f9 100644 --- a/src/char/char_clif.c +++ b/src/char/char_clif.c @@ -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 .L .L +/// HC: <082a>.W .L .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 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;