From f20c6c19cda1c672ed93836ddd33ce8e08e104c9 Mon Sep 17 00:00:00 2001 From: ultramage Date: Thu, 18 Oct 2007 12:49:49 +0000 Subject: * Removed commented-out code for check_fake_id() * Merged improved/cleaned up (WiP) code for clif_parse_WisMessage * Removed the requirement to provide a character name in the message string when calling is_atcommand() (needed for the previous fix) - currently both ways work, but old will be removed in the upcoming command cleanup so please adjust your custom code if you use this! * Added clif_process_message(), an unified way to validate all four types of player message packets and retrieve their components * Applied the new checking function to clif code, this fixes various length mismatches caused by incomplete code in r11386 (bugreport:198) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11507 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 11 ++ src/common/mmo.h | 6 +- src/common/socket.c | 2 - src/map/atcommand.c | 14 +- src/map/charcommand.c | 14 +- src/map/chrif.h | 1 - src/map/clif.c | 494 ++++++++++++++++++++++---------------------------- src/map/clif.h | 1 - src/map/guild.c | 4 +- src/map/guild.h | 4 +- src/map/intif.c | 4 +- src/map/intif.h | 4 +- src/map/party.c | 4 +- src/map/party.h | 4 +- 14 files changed, 257 insertions(+), 310 deletions(-) diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 2c4930c1e..af3d4af01 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,17 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/10/18 + * Applied the new checking function to clif code, this fixes various + length mismatches caused by incomplete code in r11386 + * Added clif_process_message(), an unified way to validate all four + types of player message packets and retrieve their components + * Removed the requirement to provide a character name in the message + string when calling is_atcommand() (needed for the previous fix) + - currently both ways work, but old will be removed in the upcoming + command cleanup so please adjust your custom code if you use this! + * Merged improved/cleaned up (WiP) code for clif_parse_WisMessage + * Removed commented-out code for check_fake_id() [ultramage] 2007/10/17 * Removed outdated copyright and version number from startup logo * Removed socket code that attempts to cope with code bugs at runtime diff --git a/src/common/mmo.h b/src/common/mmo.h index ddc43ebbf..18b724e56 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -74,12 +74,12 @@ //For character names, title names, guilds, maps, etc. //Includes null-terminator as it is the length of the array. -#define NAME_LENGTH 24 +#define NAME_LENGTH (23 + 1) //For item names, which tend to have much longer names. #define ITEM_NAME_LENGTH 50 //For Map Names, which the client considers to be 16 in length including the .gat extension -#define MAP_NAME_LENGTH 12 -#define MAP_NAME_LENGTH_EXT 16 +#define MAP_NAME_LENGTH (11 + 1) +#define MAP_NAME_LENGTH_EXT (MAP_NAME_LENGTH + 4) #define MAX_FRIENDS 40 #define MAX_MEMOPOINTS 10 diff --git a/src/common/socket.c b/src/common/socket.c index d8f3365d3..ef8e99762 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -198,8 +198,6 @@ int send_from_fifo(int fd) if( session[fd]->wdata_size == 0 ) return 0; // nothing to send - ShowInfo("Session #%d sending %d bytes.\n", fd, session[fd]->wdata_size); - len = send(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, 0); if( len == SOCKET_ERROR ) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index e6b1fd6e0..dd022b9c8 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -719,11 +719,15 @@ AtCommandType is_atcommand(const int fd, struct map_session_data* sd, const char if (!message || !*message) return AtCommand_None; - str += strlen(sd->status.name); - while (*str && (ISSPACE(*str) || (s_flag == 0 && *str == ':'))) { - if (*str == ':') - s_flag = 1; - str++; + // temporary compatibility layer for previous implementation + if( *message != atcommand_symbol ) + { + str += strlen(sd->status.name); + while (*str && (ISSPACE(*str) || (s_flag == 0 && *str == ':'))) { + if (*str == ':') + s_flag = 1; + str++; + } } if (!*str) diff --git a/src/map/charcommand.c b/src/map/charcommand.c index dc16f399b..d5f819625 100644 --- a/src/map/charcommand.c +++ b/src/map/charcommand.c @@ -287,11 +287,15 @@ CharCommandType is_charcommand(const int fd, struct map_session_data* sd, const if (!message || !*message) return CharCommand_None; - str += strlen(sd->status.name); - while (*str && (ISSPACE(*str) || (s_flag == 0 && *str == ':'))) { - if (*str == ':') - s_flag = 1; - str++; + // temporary compatibility layer for previous implementation + if( *message != charcommand_symbol ) + { + str += strlen(sd->status.name); + while (*str && (ISSPACE(*str) || (s_flag == 0 && *str == ':'))) { + if (*str == ':') + s_flag = 1; + str++; + } } if (!*str) diff --git a/src/map/chrif.h b/src/map/chrif.h index ad39c966a..b4e9062dc 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -28,7 +28,6 @@ void chrif_authok(int fd); int chrif_scdata_request(int account_id, int char_id); int chrif_save(struct map_session_data* sd, int flag); int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip); -void check_fake_id(int fd, struct map_session_data *sd, int target_id); int chrif_changemapserver(struct map_session_data* sd, short map, int x, int y, uint32 ip, uint16 port); int chrif_searchcharid(int char_id); diff --git a/src/map/clif.c b/src/map/clif.c index de0031fb7..0ace107aa 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -4979,16 +4979,15 @@ void clif_upgrademessage(int fd, int result, int item_id) /*========================================== * Wisp/page is transmitted to the destination player + * R 0097 .w .24B .?B *------------------------------------------*/ -int clif_wis_message(int fd, const char* nick, const char* mes, int mes_len) // R 0097 .w .24B .?B +int clif_wis_message(int fd, const char* nick, const char* mes, int mes_len) { -// printf("clif_wis_message(%d, %s, %s)\n", fd, nick, mes); - WFIFOHEAD(fd, mes_len + NAME_LENGTH + 4); WFIFOW(fd,0) = 0x97; WFIFOW(fd,2) = mes_len + NAME_LENGTH + 4; - memcpy(WFIFOP(fd,4), nick, NAME_LENGTH); - memcpy(WFIFOP(fd,28), mes, mes_len); + safestrncpy((char*)WFIFOP(fd,4), nick, NAME_LENGTH); + safestrncpy((char*)WFIFOP(fd,28), mes, mes_len); WFIFOSET(fd,WFIFOW(fd,2)); return 0; } @@ -7233,6 +7232,24 @@ int clif_specialeffect(struct block_list* bl, int type, enum send_target target) return 0; } +// messages (from mobs/npcs) [Valaris] +int clif_message(struct block_list* bl, const char* msg) +{ + unsigned short msg_len = strlen(msg) + 1; + uint8 buf[256]; + + nullpo_retr(0, bl); + + WBUFW(buf,0) = 0x8d; + WBUFW(buf,2) = msg_len + 8; + WBUFL(buf,4) = bl->id; + memcpy(WBUFP(buf,8), msg, msg_len); + + clif_send(buf, WBUFW(buf,2), bl, AREA_CHAT_WOC); + + return 0; +} + // refresh the client's screen, getting rid of any effects int clif_refresh(struct map_session_data *sd) { @@ -7607,6 +7624,104 @@ void clif_feel_hate_reset(struct map_session_data *sd) WFIFOSET(fd, packet_len(0x20e)); } +/// Validates one global/guild/party/whisper message packet to and tries to recognize its components. +/// Returns true if the packet was parsed successfully. +/// Formats: 0 - .w .w ( : ).?B 00 +/// 1 - .w .w .24B .?B 00 +static bool clif_process_message(struct map_session_data* sd, int format, const char** name_, int* namelen_, const char** message_, int* messagelen_) +{ + const char *text, *name, *message; + unsigned int packetlen, textlen, namelen, messagelen; + int fd = sd->fd; + + *name_ = NULL; + *namelen_ = 0; + *message_ = NULL; + *messagelen_ = 0; + + packetlen = RFIFOW(fd,2); + // basic structure checks + if( packetlen > RFIFOREST(fd) ) + { // there has to be enough data to read + ShowWarning("clif_process_message: Received malformed packet from player '%s' (packet length is incorrect)!\n", sd->status.name); + return false; + } + if( packetlen < 4 + 1 ) + { // 4-byte header and at least an empty string is expected + ShowWarning("clif_process_message: Received malformed packet from player '%s' (no message data)!\n", sd->status.name); + return false; + } + + text = (char*)RFIFOP(fd,4); + textlen = packetlen - 4; + + // process part of the packet + if( format == 0 ) + {// name and message are separated by ' : ' + // validate name + name = text; + namelen = strnlen(sd->status.name, NAME_LENGTH-1); // name length (w/o zero byte) + + if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name + name[namelen] != ' ' || name[namelen+1] != ':' || name[namelen+2] != ' ' ) // followed by ' : ' + { + //Hacked message, or infamous "client desynch" issue where they pick one char while loading another. + ShowWarning("clif_process_message: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name); + clif_setwaitclose(fd); // Just kick them out to correct it. + return false; + } + + message = name + namelen + 3; + messagelen = textlen - namelen - 3; // this should be the message length (w/ zero byte included) + } + else + {// name has fixed width + if( textlen < NAME_LENGTH + 1 ) + { + ShowWarning("clif_process_message: Received malformed packet from player '%s' (packet length is incorrect)!\n", sd->status.name); + return false; + } + + // validate name + name = text; + namelen = strnlen(name, NAME_LENGTH-1); // name length (w/o zero byte) + + if( name[namelen] != '\0' ) + { // only restriction is that the name must be zero-terminated + ShowWarning("clif_process_message: Player '%s' sent an unterminated name!\n", sd->status.name); + return false; + } + + message = name + NAME_LENGTH; + messagelen = textlen - NAME_LENGTH; // this should be the message length (w/ zero byte included) + } + + if( messagelen != strnlen(message, messagelen)+1 ) + { // the declared length must match real length + ShowWarning("clif_process_message: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name); + return false; + } + // verify part of the packet + if( message[messagelen-1] != '\0' ) + { // message must be zero-terminated + ShowWarning("clif_process_message: Player '%s' sent an unterminated message string!\n", sd->status.name); + return false; + } + if( messagelen > CHAT_SIZE_MAX ) + { // messages mustn't be too long + // Normally you can only enter CHATBOX_SIZE-1 chars into the chat box, but Frost Joke / Dazzler's text can be longer. + // Neither the official client nor server place any restriction on the length of the text in the packet, + // but we'll only allow reasonably long strings here. This also makes sure all strings fit into the `chatlog` table. + ShowWarning("clif_process_message: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX, message); + return false; + } + + *name_ = name; + *namelen_ = namelen; + *message_ = message; + *messagelen_ = messagelen; + return true; +} // --------------------- // clif_guess_PacketVer @@ -8079,99 +8194,6 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd) WFIFOSET(fd,packet_len(0x18b)); } - -/*========================================== - * - *------------------------------------------*/ -void check_fake_id(int fd, struct map_session_data *sd, int target_id) -{ - // if player asks for the fake player (only bot and modified client can see a hiden player) -/* if (target_id == server_char_id) { - char message_to_gm[strlen(msg_txt(536)) + strlen(msg_txt(540)) + strlen(msg_txt(507)) + strlen(msg_txt(508))]; - sprintf(message_to_gm, msg_txt(536), sd->status.name, sd->status.account_id); // Character '%s' (account: %d) try to use a bot (it tries to detect a fake player). - intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm); - // if we block people - if (battle_config.ban_bot < 0) { - chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block - clif_setwaitclose(sd->fd); // forced to disconnect because of the hack - // message about the ban - sprintf(message_to_gm, msg_txt(540)); // This player has been definitivly blocked. - // if we ban people - } else if (battle_config.ban_bot > 0) { - chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_bot, 0); // type: 2 - ban (year, month, day, hour, minute, second) - clif_setwaitclose(sd->fd); // forced to disconnect because of the hack - // message about the ban - sprintf(message_to_gm, msg_txt(507), battle_config.ban_bot); // This player has been banned for %d minute(s). - } else { // impossible to display: we don't send fake player if battle_config.ban_bot is == 0 - // message about the ban - sprintf(message_to_gm, msg_txt(508)); // This player hasn't been banned (Ban option is disabled). - } - intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm); - // send this info cause the bot ask until get an answer, damn spam - memset(WPACKETP(0), 0, packet_len(0x95)); - WPACKETW(0) = 0x95; - WPACKETL(2) = server_char_id; - strncpy(WPACKETP(6), sd->status.name, 24); - SENDPACKET(fd, packet_len(0x95)); - // take fake player out of screen - WPACKETW(0) = 0x80; - WPACKETL(2) = server_char_id; - WPACKETB(6) = 0; - SENDPACKET(fd, packet_len(0x80)); - // take fake mob out of screen - WPACKETW(0) = 0x80; - WPACKETL(2) = server_fake_mob_id; - WPACKETB(6) = 0; - SENDPACKET(fd, packet_len(0x80)); - } - - // if player asks for the fake mob (only bot and modified client can see a hiden mob) - if (target_id == server_fake_mob_id) { - int fake_mob; - char message_to_gm[strlen(msg_txt(537)) + strlen(msg_txt(540)) + strlen(msg_txt(507)) + strlen(msg_txt(508))]; - sprintf(message_to_gm, msg_txt(537), sd->status.name, sd->status.account_id); // Character '%s' (account: %d) try to use a bot (it tries to detect a fake mob). - intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm); - // if we block people - if (battle_config.ban_bot < 0) { - chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block - clif_setwaitclose(sd->fd); // forced to disconnect because of the hack - // message about the ban - sprintf(message_to_gm, msg_txt(540)); // This player has been definitivly blocked. - // if we ban people - } else if (battle_config.ban_bot > 0) { - chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_bot, 0); // type: 2 - ban (year, month, day, hour, minute, second) - clif_setwaitclose(sd->fd); // forced to disconnect because of the hack - // message about the ban - sprintf(message_to_gm, msg_txt(507), battle_config.ban_bot); // This player has been banned for %d minute(s). - } else { // impossible to display: we don't send fake player if battle_config.ban_bot is == 0 - // message about the ban - sprintf(message_to_gm, msg_txt(508)); // This player hasn't been banned (Ban option is disabled). - } - intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm); - // send this info cause the bot ask until get an answer, damn spam - memset(WPACKETP(0), 0, packet_len(0x95)); - WPACKETW(0) = 0x95; - WPACKETL(2) = server_fake_mob_id; - fake_mob = fake_mob_list[(sd->bl.m + sd->fd + sd->status.char_id) % ARRAYLENGTH(fake_mob_list)]; // never same mob - if (!mobdb_checkid(fake_mob)) - fake_mob = 1002; // poring (default) - strncpy(WPACKETP(6), mob_db[fake_mob].name, 24); - SENDPACKET(fd, packet_len(0x95)); - // take fake mob out of screen - WPACKETW(0) = 0x80; - WPACKETL(2) = server_fake_mob_id; - WPACKETB(6) = 0; - SENDPACKET(fd, packet_len(0x80)); - // take fake player out of screen - WPACKETW(0) = 0x80; - WPACKETL(2) = server_char_id; - WPACKETB(6) = 0; - SENDPACKET(fd, packet_len(0x80)); - } -*/ - return; -} - /*========================================== * *------------------------------------------*/ @@ -8215,60 +8237,17 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) { - const char *text, *name, *message; - unsigned int packetlen, textlen, namelen, messagelen; - - packetlen = RFIFOW(fd,2); - // basic structure checks - if( packetlen > RFIFOREST(fd) ) - { // there has to be enough data to read - ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name); - return; - } - if( packetlen < 4 + 1 ) - { // 4-byte header and at least an empty string is expected - ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (no message data)!\n", sd->status.name); - return; - } + const char* text = (char*)RFIFOP(fd,4); + int textlen = RFIFOW(fd,2) - 4; - text = (char*)RFIFOP(fd,4); - textlen = packetlen - 4; + const char *name, *message; + int namelen, messagelen; - name = text; - namelen = strnlen(sd->status.name, NAME_LENGTH - 1); - // verify part of the packet - if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name - name[namelen] != ' ' || name[namelen+1] != ':' || name[namelen+2] != ' ' ) // followed by ' : ' - { - //Hacked message, or infamous "client desynch" issue where they pick one char while loading another. - ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name); - clif_setwaitclose(fd); // Just kick them out to correct it. + // validate packet and retrieve name and message + if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - } - message = text + namelen + 3; - messagelen = textlen - namelen - 3; // this should be the message length (w/ zero byte included) - // verify part of the packet - if( message[messagelen-1] != '\0' ) - { // message must be zero-terminated - ShowWarning("clif_parse_GlobalMessage: Player '%s' sent an unterminated string!\n", sd->status.name); - return; - } - if( messagelen != strnlen(message, messagelen)+1 ) - { // the declared length must match real length - ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name); - return; - } - if( messagelen > CHAT_SIZE_MAX ) - { // messages mustn't be too long - // Normally you can only enter CHATBOX_SIZE-1 chars into the chat box, but Frost Joke / Dazzler's text can be longer. - // Neither the official client nor server place any restriction on the length of the text in the packet, - // but we'll only allow reasonably long strings here. This also makes sure all strings fit into the `chatlog` table. - ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX, message); - return; - } - - if( is_atcommand(fd, sd, text) != AtCommand_None || is_charcommand(fd, sd, text) != CharCommand_None ) + if( is_atcommand(fd, sd, message) != AtCommand_None || is_charcommand(fd, sd, message) != CharCommand_None ) return; if( sd->sc.data[SC_BERSERK].timer != -1 || (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) ) @@ -8281,7 +8260,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - // send message to others + // send message to others (using the send buffer for temp. storage) WFIFOHEAD(fd, 8 + textlen); WFIFOW(fd,0) = 0x8d; WFIFOW(fd,2) = 8 + textlen; @@ -8290,7 +8269,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) clif_send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC); // send back message to the speaker - memcpy(WFIFOP(fd,0), RFIFOP(fd,0), packetlen); + memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2)); WFIFOW(fd,0) = 0x8e; WFIFOSET(fd, WFIFOW(fd,2)); @@ -8340,23 +8319,6 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) return; } -int clif_message(struct block_list *bl, const char* msg) -{ - unsigned short msg_len = strlen(msg) + 1; - unsigned char buf[256]; - - nullpo_retr(0, bl); - - WBUFW(buf, 0) = 0x8d; - WBUFW(buf, 2) = msg_len + 8; - WBUFL(buf, 4) = bl->id; - memcpy(WBUFP(buf, 8), msg, msg_len); - - clif_send(buf, WBUFW(buf,2), bl, AREA_CHAT_WOC); // by Gengar - - return 0; -} - /*========================================== * /mm /mapmove (as @rura GM command) *------------------------------------------*/ @@ -8581,180 +8543,143 @@ void clif_parse_Restart(int fd, struct map_session_data *sd) } /*========================================== - * Transmission of a wisp (S 0096 .w .24B .?B) + * Validates and processes whispered messages + * S 0096 .w .23B 00 .?B *------------------------------------------*/ -void clif_parse_Wis(int fd, struct map_session_data* sd) +void clif_parse_WisMessage(int fd, struct map_session_data* sd) { - char *command, *msg; - struct map_session_data *dstsd; - int i=0; - struct npc_data *npc; - char split_data[10][50]; - char target[NAME_LENGTH+1]; - char output[256]; - unsigned int len; - - len = RFIFOW(fd,2); //Packet length - if (len < 28) - { //Invalid packet, specified size is less than minimum! [Skotlex] - ShowWarning("Hack on Whisper: %s (AID/CID: %d:%d)!\n", sd->status.name, sd->status.account_id, sd->status.char_id); - clif_setwaitclose(fd); + struct map_session_data* dstsd; + int i; + + char *target, *message; + int namelen, messagelen; + + // validate packet and retrieve name and message + if( !clif_process_message(sd, 1, &target, &namelen, &message, &messagelen) ) return; - } - if (len == 28) return; //Not sure if client really lets you send a blank line. - len-=28; //Message length - // 24+3+(RFIFOW(fd,2)-28)+1 <- last 1 is '\0' - command = (char*)aMallocA((NAME_LENGTH+4+len) * sizeof(char)); - //No need for out of memory checks, malloc.c aborts the map when that happens. - msg = command; - msg+= sprintf(command, "%s : ", sd->status.name); - memcpy(msg, RFIFOP(fd, 28), len); - mes_len_check(msg, len, CHATBOX_SIZE); - if ((is_charcommand(fd, sd, command) != CharCommand_None) || (is_atcommand(fd, sd, command) != AtCommand_None)) { - aFree(command); + if (is_atcommand(fd, sd, message) != AtCommand_None || is_charcommand(fd, sd, message) != CharCommand_None ) return; - } - if (sd->sc.count && - (sd->sc.data[SC_BERSERK].timer!=-1 || - (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT))) { - aFree(command); + + if (sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)) return; - } if (battle_config.min_chat_delay) { //[Skotlex] if (DIFF_TICK(sd->cantalk_tick, gettick()) > 0) { - aFree(command); return; } sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - memcpy(&target,RFIFOP(fd, 4),NAME_LENGTH); - target[NAME_LENGTH]='\0'; - // Chat logging type 'W' / Whisper if( log_config.chat&1 || (log_config.chat&4 && !(agit_flag && log_config.chat&64)) ) - log_chat("W", 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, target, msg); + log_chat("W", 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, target, message); //-------------------------------------------------------// // Lordalfa - Paperboy - To whisper NPC commands // //-------------------------------------------------------// - if (target[0] && (strncasecmp(target,"NPC:",4) == 0) && (strlen(target) >4)) { - char *str= target+4; //Skip the NPC: string part. + if (target[0] && (strncasecmp(target,"NPC:",4) == 0) && (strlen(target) > 4)) + { + char* str = target+4; //Skip the NPC: string part. + struct npc_data* npc; if ((npc = npc_name2id(str))) { + char split_data[10][50]; char *split; - str = msg; - for( i=0; i < 10; ++i ) + char output[256]; + + str = message; + for( i = 0; i < 10; ++i ) {// Splits the message using '#' as separators split = strchr(str,'#'); if( split == NULL ) { // use the remaining string - strncpy(split_data[i], str, sizeof(split_data[0])/sizeof(char)); - split_data[i][sizeof(split_data[0])/sizeof(char)-1] = '\0'; + safestrncpy(split_data[i], str, ARRAYLENGTH(split_data[i])); for( ++i; i < 10; ++i ) split_data[i][0] = '\0'; break; } *split = '\0'; - strncpy(split_data[i], str, sizeof(split_data[0])/sizeof(char)); - split_data[i][sizeof(split_data[0])/sizeof(char)-1] = '\0'; + safestrncpy(split_data[i], str, ARRAYLENGTH(split_data[i])); str = split+1; } - for (i=0;i<10;i++) + for( i = 0; i < 10; ++i ) { sprintf(output, "@whispervar%d$", i); set_var(sd,output,(char *) split_data[i]); } sprintf(output, "%s::OnWhisperGlobal", npc->name); - npc_event(sd,output,0); // Calls the NPC label + npc_event(sd,output,0); // Calls the NPC label - aFree(command); - return; + return; } } // Main chat [LuzZza] - if(strcmpi(target, main_chat_nick) == 0) { + if(strcmpi(target, main_chat_nick) == 0) + { if(!sd->state.mainchat) clif_displaymessage(fd, msg_txt(388)); // You should enable main chat with "@main on" command. else { - snprintf(output, sizeof(output)/sizeof(char), msg_txt(386), sd->status.name, msg); + char output[256]; + snprintf(output, ARRAYLENGTH(output), msg_txt(386), sd->status.name, message); intif_announce(output, strlen(output) + 1, 0xFE000000, 0); } - aFree(command); return; } // searching destination character dstsd = map_nick2sd(target); - // player is not on this map-server - // At this point, don't send wisp/page if it's not exactly the same name, because (example) - // if there are 'Test' player on an other map-server and 'test' player on this map-server, - // and if we ask for 'Test', we must not contact 'test' player - // so, we send information to inter-server, which is the only one which decide (and copy correct name). + if (dstsd == NULL || strcmp(dstsd->status.name, target) != 0) - { // send message to inter-server - intif_wis_message(sd, target, msg, len); - aFree(command); - return; - } - // player is on this map-server - if (dstsd->fd == fd) { - // if you send to your self, don't send anything to others - // but, normally, it's impossible! - clif_wis_message(fd, wisp_server_name, - "You can not page yourself. Sorry.", - strlen("You can not page yourself. Sorry.") + 1); - aFree(command); + { + // player is not on this map-server + // At this point, don't send wisp/page if it's not exactly the same name, because (example) + // if there are 'Test' player on an other map-server and 'test' player on this map-server, + // and if we ask for 'Test', we must not contact 'test' player + // so, we send information to inter-server, which is the only one which decide (and copy correct name). + intif_wis_message(sd, target, message, messagelen); return; } - // otherwise, send message and answer immediately - if (dstsd->state.ignoreAll) { + + // if player ignores everyone + if (dstsd->state.ignoreAll) + { if (dstsd->sc.option & OPTION_INVISIBLE && pc_isGM(sd) < pc_isGM(dstsd)) clif_wis_end(fd, 1); // 1: target character is not loged in else clif_wis_end(fd, 3); // 3: everyone ignored by target - aFree(command); return; } - // if player ignore the source character - for(i = 0; i < MAX_IGNORE_LIST && - dstsd->ignore[i].name[0] != '\0' && - strcmp(dstsd->ignore[i].name, sd->status.name) != 0 - ; i++); - + // if player ignores the source character + ARR_FIND(0, MAX_IGNORE_LIST, i, dstsd->ignore[i].name[0] == '\0' || strcmp(dstsd->ignore[i].name, sd->status.name) == 0); if(i < MAX_IGNORE_LIST && dstsd->ignore[i].name[0] != '\0') - { //Ignored - clif_wis_end(fd, 2); // 2: ignored by target - aFree(command); + { // source char present in ignore list + clif_wis_end(fd, 2); // 2: ignored by target return; } - // if source player not found in ignore list - if(dstsd->away_message[0] != '\0') { // Send away automessage [LuzZza] - //(Automessage has been sent) - sprintf(output, "%s %s", msg, msg_txt(543)); + // notify sender of success + clif_wis_end(fd, 0); // 0: success to send wisper + + // if player has an auto-away message + if(dstsd->away_message[0] != '\0') + { + char output[256]; + sprintf(output, "%s %s", message, msg_txt(543)); // "(Automessage has been sent)" clif_wis_message(dstsd->fd, sd->status.name, output, strlen(output) + 1); - clif_wis_end(fd, 0); // 0: success to send wisper if(dstsd->state.autotrade) - //"Away [AT] - \"%s\"" - sprintf(output, msg_txt(544), dstsd->away_message); + sprintf(output, msg_txt(544), dstsd->away_message); // "Away [AT] - "%s"" else - //"Away - \"%s\"" - sprintf(output, msg_txt(545), dstsd->away_message); - aFree(command); + sprintf(output, msg_txt(545), dstsd->away_message); // "Away - "%s"" clif_wis_message(fd, dstsd->status.name, output, strlen(output) + 1); return; } // Normal message - clif_wis_message(dstsd->fd, sd->status.name, msg, len); - clif_wis_end(fd, 0); // 0: success to send wisper - aFree(command); + clif_wis_message(dstsd->fd, sd->status.name, message, messagelen); return; } @@ -10020,14 +9945,20 @@ void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd) } /*========================================== - * パーティメッセージ送信要求 + * Validates and processes party messages + * S 0108 .w .?B ( : ) 00 *------------------------------------------*/ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) { - int len = RFIFOW(fd,2) - 4; - char* message = (char*)RFIFOP(fd,4); + const char* text = (char*)RFIFOP(fd,4); + int textlen = RFIFOW(fd,2) - 4; + + const char *name, *message; + int namelen, messagelen; - mes_len_check(message, len, CHATBOX_SIZE); + // validate packet and retrieve name and message + if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) ) + return; if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None) return; @@ -10042,7 +9973,7 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - party_send_message(sd, message, len); + party_send_message(sd, text, textlen); } /*========================================== @@ -10287,14 +10218,20 @@ void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd) } /*========================================== - * ギルド会話 + * Validates and processes guild messages + * S 017e .w .?B ( : ) 00 *------------------------------------------*/ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) { - int len = RFIFOW(fd,2) - 4; - char* message = (char*)RFIFOP(fd,4); + const char* text = (char*)RFIFOP(fd,4); + int textlen = RFIFOW(fd,2) - 4; - mes_len_check(message, len, CHATBOX_SIZE); + const char *name, *message; + int namelen, messagelen; + + // validate packet and retrieve name and message + if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) ) + return; if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None) return; @@ -10309,7 +10246,7 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - guild_send_message(sd, message, len); + guild_send_message(sd, text, textlen); } /*========================================== @@ -11064,12 +11001,7 @@ void clif_parse_FriendsListRemove(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_GMKillAll(int fd, struct map_session_data* sd) { - char message[50]; - - strncpy(message,sd->status.name, NAME_LENGTH); - is_atcommand(fd, sd, strcat(message," : @kickall")); - - return; + is_atcommand(fd, sd, "@kickall"); } /*========================================== @@ -11646,7 +11578,7 @@ static int packetdb_readdb(void) {clif_parse_HowManyConnections,"howmanyconnections"}, {clif_parse_ActionRequest,"actionrequest"}, {clif_parse_Restart,"restart"}, - {clif_parse_Wis,"wis"}, + {clif_parse_WisMessage,"wis"}, {clif_parse_GMmessage,"gmmessage"}, {clif_parse_TakeItem,"takeitem"}, {clif_parse_DropItem,"dropitem"}, diff --git a/src/map/clif.h b/src/map/clif.h index 8406bd9f7..0b1ffe52c 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -89,7 +89,6 @@ int clif_authok(struct map_session_data *); int clif_authfail_fd(int,int); void clif_updatemaxid(int, int); int clif_charselectok(int); -void check_fake_id(int fd, struct map_session_data *sd, int target_id); int clif_dropflooritem(struct flooritem_data *); int clif_clearflooritem(struct flooritem_data *,int); diff --git a/src/map/guild.c b/src/map/guild.c index 3207dd398..1fda18d9f 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -995,7 +995,7 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin return 0; } // ギルド会話送信 -int guild_send_message(struct map_session_data *sd,char *mes,int len) +int guild_send_message(struct map_session_data *sd,const char *mes,int len) { nullpo_retr(0, sd); @@ -1011,7 +1011,7 @@ int guild_send_message(struct map_session_data *sd,char *mes,int len) return 0; } // ギルド会話受信 -int guild_recv_message(int guild_id,int account_id,char *mes,int len) +int guild_recv_message(int guild_id,int account_id,const char *mes,int len) { struct guild *g; if( (g=guild_search(guild_id))==NULL) diff --git a/src/map/guild.h b/src/map/guild.h index f1bb836ea..b7b5f2ac4 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -71,8 +71,8 @@ int guild_change_notice(struct map_session_data *sd,int guild_id,const char *mes int guild_notice_changed(int guild_id,const char *mes1,const char *mes2); int guild_change_emblem(struct map_session_data *sd,int len,const char *data); int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data); -int guild_send_message(struct map_session_data *sd,char *mes,int len); -int guild_recv_message(int guild_id,int account_id,char *mes,int len); +int guild_send_message(struct map_session_data *sd,const char *mes,int len); +int guild_recv_message(int guild_id,int account_id,const char *mes,int len); int guild_send_dot_remove(struct map_session_data *sd); int guild_skillupack(int guild_id,int skill_num,int account_id); int guild_break(struct map_session_data *sd,char *name); diff --git a/src/map/intif.c b/src/map/intif.c index b6f457ee1..3bf2d45ae 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -480,7 +480,7 @@ int intif_break_party(int party_id) return 0; } // パーティ会話送信 -int intif_party_message(int party_id,int account_id,char *mes,int len) +int intif_party_message(int party_id,int account_id,const char *mes,int len) { if (CheckForCharServer()) return 0; @@ -623,7 +623,7 @@ int intif_guild_break(int guild_id) return 0; } // ギルド会話送信 -int intif_guild_message(int guild_id,int account_id,char *mes,int len) +int intif_guild_message(int guild_id,int account_id,const char *mes,int len) { if (CheckForCharServer()) return 0; diff --git a/src/map/intif.h b/src/map/intif.h index 7f7cfb392..5487d5725 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -36,7 +36,7 @@ int intif_party_changeoption(int party_id, int account_id, int exp, int item); int intif_party_leave(int party_id,int account_id, int char_id); int intif_party_changemap(struct map_session_data *sd, int online); int intif_break_party(int party_id); -int intif_party_message(int party_id, int account_id, char *mes,int len); +int intif_party_message(int party_id, int account_id, const char *mes,int len); int intif_party_checkconflict(int party_id,int account_id,int char_id); int intif_party_leaderchange(int party_id,int account_id,int char_id); @@ -47,7 +47,7 @@ int intif_guild_addmember(int guild_id, struct guild_member *m); int intif_guild_leave(int guild_id, int account_id, int char_id, int flag, const char *mes); int intif_guild_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int class_); int intif_guild_break(int guild_id); -int intif_guild_message(int guild_id, int account_id, char *mes, int len); +int intif_guild_message(int guild_id, int account_id, const char *mes, int len); int intif_guild_checkconflict(int guild_id, int account_id, int char_id); int intif_guild_change_gm(int guild_id, const char* name, int len); int intif_guild_change_basicinfo(int guild_id, int type, const void *data, int len); diff --git a/src/map/party.c b/src/map/party.c index 68a209172..a81c7dc42 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -600,7 +600,7 @@ int party_send_logout(struct map_session_data *sd) return 1; } -int party_send_message(struct map_session_data *sd,char *mes,int len) +int party_send_message(struct map_session_data *sd,const char *mes,int len) { if(sd->status.party_id==0) return 0; @@ -614,7 +614,7 @@ int party_send_message(struct map_session_data *sd,char *mes,int len) return 0; } -int party_recv_message(int party_id,int account_id,char *mes,int len) +int party_recv_message(int party_id,int account_id,const char *mes,int len) { struct party_data *p; if( (p=party_search(party_id))==NULL) diff --git a/src/map/party.h b/src/map/party.h index b3a5b9a4c..c32863602 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -38,8 +38,8 @@ int party_changeoption(struct map_session_data *sd,int exp,int item); void party_send_movemap(struct map_session_data *sd); void party_send_levelup(struct map_session_data *sd); int party_send_logout(struct map_session_data *sd); -int party_send_message(struct map_session_data *sd,char *mes,int len); -int party_recv_message(int party_id,int account_id,char *mes,int len); +int party_send_message(struct map_session_data *sd,const char *mes,int len); +int party_recv_message(int party_id,int account_id,const char *mes,int len); int party_check_conflict(struct map_session_data *sd); int party_skill_check(struct map_session_data *sd, int party_id, int skillid, int skilllv); int party_send_xy_clear(struct party_data *p); -- cgit v1.2.3-60-g2f50