2011-04-27 16:22:42 +06:00
/*
2014-01-01 00:07:53 +01:00
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
2011-04-27 16:22:42 +06:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ChatLink.h"
#include "SpellMgr.h"
#include "ObjectMgr.h"
2011-07-26 23:09:28 +02:00
#include "SpellInfo.h"
2012-11-17 05:18:37 +01:00
#include "DBCStores.h"
2012-11-27 13:02:04 +01:00
#include "AchievementMgr.h"
2011-04-27 16:22:42 +06:00
// Supported shift-links (client generated and server side)
// |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r
// - client, item icon shift click, not used in server currently
// |color|Harea:area_id|h[name]|h|r
// |color|Hcreature:creature_guid|h[name]|h|r
// |color|Hcreature_entry:creature_id|h[name]|h|r
// |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r - client, at shift click in recipes list dialog
// |color|Hgameevent:id|h[name]|h|r
// |color|Hgameobject:go_guid|h[name]|h|r
// |color|Hgameobject_entry:go_id|h[name]|h|r
// |color|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|h|r - client, at shift click in glyphs dialog, GlyphSlot.dbc, GlyphProperties.dbc
// |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:0:0:0:reporter_level|h[name]|h|r
// - client, item icon shift click
// |color|Hitemset:itemset_id|h[name]|h|r
// |color|Hplayer:name|h[name]|h|r - client, in some messages, at click copy only name instead link
// |color|Hquest:quest_id:quest_level|h[name]|h|r - client, quest list name shift-click
// |color|Hskill:skill_id|h[name]|h|r
// |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click
2011-04-29 20:47:02 +02:00
// |color|Htalent:talent_id, rank|h[name]|h|r - client, talent icon shift-click
2011-04-27 16:22:42 +06:00
// |color|Htaxinode:id|h[name]|h|r
// |color|Htele:id|h[name]|h|r
// |color|Htitle:id|h[name]|h|r
// |color|Htrade:spell_id:cur_value:max_value:unk3int:unk3str|h[name]|h|r - client, spellbook profession icon shift-click
inline bool ReadUInt32 ( std :: istringstream & iss , uint32 & res )
{
iss >> std :: dec >> res ;
return ! iss . fail () && ! iss . eof ();
}
inline bool ReadInt32 ( std :: istringstream & iss , int32 & res )
{
iss >> std :: dec >> res ;
return ! iss . fail () && ! iss . eof ();
}
inline std :: string ReadSkip ( std :: istringstream & iss , char term )
{
std :: string res ;
char c = iss . peek ();
while ( c != term && c != '\0' )
{
res += c ;
iss . ignore ( 1 );
c = iss . peek ();
}
return res ;
}
inline bool CheckDelimiter ( std :: istringstream & iss , char delimiter , const char * context )
{
char c = iss . peek ();
if ( c != delimiter )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): invalid %s link structure ('%c' expected, '%c' found)" , iss . str (). c_str (), context , delimiter , c );
2011-04-27 16:22:42 +06:00
return false ;
}
iss . ignore ( 1 );
return true ;
}
inline bool ReadHex ( std :: istringstream & iss , uint32 & res , uint32 length )
{
std :: istringstream :: pos_type pos = iss . tellg ();
iss >> std :: hex >> res ;
2011-05-07 20:09:45 +02:00
//uint32 size = uint32(iss.gcount());
2011-04-27 16:22:42 +06:00
if ( length && uint32 ( iss . tellg () - pos ) != length )
return false ;
return ! iss . fail () && ! iss . eof ();
}
#define DELIMITER ':'
#define PIPE_CHAR '|'
2011-05-07 20:09:45 +02:00
bool ChatLink :: ValidateName ( char * buffer , const char * /*context*/ )
2011-04-27 16:22:42 +06:00
{
_name = buffer ;
return true ;
}
// |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:random_property:0:reporter_level|h[name]|h|r
// |cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r
bool ItemChatLink :: Initialize ( std :: istringstream & iss )
{
// Read item entry
uint32 itemEntry = 0 ;
if ( ! ReadUInt32 ( iss , itemEntry ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate item
2011-04-28 22:42:33 +02:00
_item = sObjectMgr -> GetItemTemplate ( itemEntry );
2011-04-27 16:22:42 +06:00
if ( ! _item )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid itemEntry %u in |item command" , iss . str (). c_str (), itemEntry );
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate item's color
if ( _color != ItemQualityColors [ _item -> Quality ])
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): linked item has color %u, but user claims %u" , iss . str (). c_str (), ItemQualityColors [ _item -> Quality ], _color );
2011-04-27 16:22:42 +06:00
return false ;
}
// Number of various item properties after item entry
const uint8 propsCount = 8 ;
const uint8 randomPropertyPosition = 5 ;
for ( uint8 index = 0 ; index < propsCount ; ++ index )
{
if ( ! CheckDelimiter ( iss , DELIMITER , "item" ))
return false ;
int32 id = 0 ;
if ( ! ReadInt32 ( iss , id ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item property (%u)" , iss . str (). c_str (), index );
2011-04-27 16:22:42 +06:00
return false ;
}
if ( id && ( index == randomPropertyPosition ))
{
// Validate random property
if ( id > 0 )
{
_property = sItemRandomPropertiesStore . LookupEntry ( id );
if ( ! _property )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid item property id %u in |item command" , iss . str (). c_str (), id );
2011-04-27 16:22:42 +06:00
return false ;
}
}
else if ( id < 0 )
{
_suffix = sItemRandomSuffixStore . LookupEntry ( - id );
if ( ! _suffix )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid item suffix id %u in |item command" , iss . str (). c_str (), - id );
2011-04-27 16:22:42 +06:00
return false ;
}
}
}
_data [ index ] = id ;
}
return true ;
}
2011-09-15 14:08:17 +02:00
inline std :: string ItemChatLink :: FormatName ( uint8 index , ItemLocale const * locale , char * const * suffixStrings ) const
2011-04-27 16:22:42 +06:00
{
std :: stringstream ss ;
if ( locale == NULL || index >= locale -> Name . size ())
ss << _item -> Name1 ;
else
ss << locale -> Name [ index ];
if ( suffixStrings )
2011-07-29 14:18:28 +02:00
ss << ' ' << suffixStrings [ index ];
2011-04-27 16:22:42 +06:00
return ss . str ();
}
bool ItemChatLink :: ValidateName ( char * buffer , const char * context )
{
ChatLink :: ValidateName ( buffer , context );
char * const * suffixStrings = _suffix ? _suffix -> nameSuffix : ( _property ? _property -> nameSuffix : NULL );
2011-04-27 17:22:55 +02:00
bool res = ( FormatName ( LOCALE_enUS , NULL , suffixStrings ) == buffer );
2011-04-27 16:22:42 +06:00
if ( ! res )
{
2011-09-15 14:08:17 +02:00
ItemLocale const * il = sObjectMgr -> GetItemLocale ( _item -> ItemId );
2011-04-27 16:22:42 +06:00
for ( uint8 index = LOCALE_koKR ; index < TOTAL_LOCALES ; ++ index )
{
2011-04-27 17:22:55 +02:00
if ( FormatName ( index , il , suffixStrings ) == buffer )
2011-04-27 16:22:42 +06:00
{
res = true ;
break ;
}
}
}
if ( ! res )
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): linked item (id: %u) name wasn't found in any localization" , context , _item -> ItemId );
2011-04-27 16:22:42 +06:00
return res ;
}
// |color|Hquest:quest_id:quest_level|h[name]|h|r
// |cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r
bool QuestChatLink :: Initialize ( std :: istringstream & iss )
{
// Read quest id
uint32 questId = 0 ;
if ( ! ReadUInt32 ( iss , questId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate quest
_quest = sObjectMgr -> GetQuestTemplate ( questId );
if ( ! _quest )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): quest template %u not found" , iss . str (). c_str (), questId );
2011-04-27 16:22:42 +06:00
return false ;
}
// Check delimiter
if ( ! CheckDelimiter ( iss , DELIMITER , "quest" ))
return false ;
// Read quest level
if ( ! ReadInt32 ( iss , _questLevel ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest level" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate quest level
if ( _questLevel >= STRONG_MAX_LEVEL )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): quest level %d is too big" , iss . str (). c_str (), _questLevel );
2011-04-27 16:22:42 +06:00
return false ;
}
return true ;
}
bool QuestChatLink :: ValidateName ( char * buffer , const char * context )
{
ChatLink :: ValidateName ( buffer , context );
bool res = ( _quest -> GetTitle () == buffer );
if ( ! res )
2011-09-15 14:08:17 +02:00
if ( QuestLocale const * ql = sObjectMgr -> GetQuestLocale ( _quest -> GetQuestId ()))
2011-04-27 16:22:42 +06:00
for ( uint8 i = 0 ; i < ql -> Title . size (); i ++ )
if ( ql -> Title [ i ] == buffer )
{
res = true ;
break ;
}
if ( ! res )
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): linked quest (id: %u) title wasn't found in any localization" , context , _quest -> GetQuestId ());
2011-04-27 16:22:42 +06:00
return res ;
}
// |color|Hspell:spell_id|h[name]|h|r
// |cff71d5ff|Hspell:21563|h[Command]|h|r
bool SpellChatLink :: Initialize ( std :: istringstream & iss )
{
if ( _color != CHAT_LINK_COLOR_SPELL )
return false ;
// Read spell id
uint32 spellId = 0 ;
if ( ! ReadUInt32 ( iss , spellId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading spell entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate spell
2011-07-26 23:09:28 +02:00
_spell = sSpellMgr -> GetSpellInfo ( spellId );
2011-04-27 16:22:42 +06:00
if ( ! _spell )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |spell command" , iss . str (). c_str (), spellId );
2011-04-27 16:22:42 +06:00
return false ;
}
return true ;
}
bool SpellChatLink :: ValidateName ( char * buffer , const char * context )
{
ChatLink :: ValidateName ( buffer , context );
// spells with that flag have a prefix of "$PROFESSION: "
if ( _spell -> Attributes & SPELL_ATTR0_TRADESPELL )
{
SkillLineAbilityMapBounds bounds = sSpellMgr -> GetSkillLineAbilityMapBounds ( _spell -> Id );
if ( bounds . first == bounds . second )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): skill line not found for spell %u" , context , _spell -> Id );
2011-04-27 16:22:42 +06:00
return false ;
}
2011-09-15 14:08:17 +02:00
SkillLineAbilityEntry const * skillInfo = bounds . first -> second ;
2011-04-27 16:22:42 +06:00
if ( ! skillInfo )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): skill line ability not found for spell %u" , context , _spell -> Id );
2011-04-27 16:22:42 +06:00
return false ;
}
2011-09-15 14:08:17 +02:00
SkillLineEntry const * skillLine = sSkillLineStore . LookupEntry ( skillInfo -> skillId );
2011-04-27 16:22:42 +06:00
if ( ! skillLine )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): skill line not found for skill %u" , context , skillInfo -> skillId );
2011-04-27 16:22:42 +06:00
return false ;
}
for ( uint8 i = 0 ; i < TOTAL_LOCALES ; ++ i )
{
uint32 skillLineNameLength = strlen ( skillLine -> name [ i ]);
if ( skillLineNameLength > 0 && strncmp ( skillLine -> name [ i ], buffer , skillLineNameLength ) == 0 )
{
// found the prefix, remove it to perform spellname validation below
// -2 = strlen(": ")
uint32 spellNameLength = strlen ( buffer ) - skillLineNameLength - 2 ;
2014-04-04 22:16:14 +02:00
memmove ( buffer , buffer + skillLineNameLength + 2 , spellNameLength + 1 );
break ;
2011-04-27 16:22:42 +06:00
}
}
}
for ( uint8 i = 0 ; i < TOTAL_LOCALES ; ++ i )
if ( * _spell -> SpellName [ i ] && strcmp ( _spell -> SpellName [ i ], buffer ) == 0 )
2012-11-27 13:02:04 +01:00
return true ;
2011-04-27 16:22:42 +06:00
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): linked spell (id: %u) name wasn't found in any localization" , context , _spell -> Id );
2012-11-27 13:02:04 +01:00
return false ;
2011-04-27 16:22:42 +06:00
}
// |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r
// |cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r
bool AchievementChatLink :: Initialize ( std :: istringstream & iss )
{
if ( _color != CHAT_LINK_COLOR_ACHIEVEMENT )
return false ;
// Read achievemnt Id
uint32 achievementId = 0 ;
if ( ! ReadUInt32 ( iss , achievementId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate achievement
2012-11-27 13:02:04 +01:00
_achievement = sAchievementMgr -> GetAchievement ( achievementId );
2011-04-27 16:22:42 +06:00
if ( ! _achievement )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid achivement id %u in |achievement command" , iss . str (). c_str (), achievementId );
2011-04-27 16:22:42 +06:00
return false ;
}
// Check delimiter
if ( ! CheckDelimiter ( iss , DELIMITER , "achievement" ))
return false ;
// Read HEX
if ( ! ReadHex ( iss , _guid , 0 ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): invalid hexadecimal number while reading char's guid" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Skip progress
const uint8 propsCount = 8 ;
for ( uint8 index = 0 ; index < propsCount ; ++ index )
{
if ( ! CheckDelimiter ( iss , DELIMITER , "achievement" ))
return false ;
if ( ! ReadUInt32 ( iss , _data [ index ]))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement property (%u)" , iss . str (). c_str (), index );
2011-04-27 16:22:42 +06:00
return false ;
}
}
return true ;
}
bool AchievementChatLink :: ValidateName ( char * buffer , const char * context )
{
ChatLink :: ValidateName ( buffer , context );
for ( uint8 i = 0 ; i < TOTAL_LOCALES ; ++ i )
if ( * _achievement -> name [ i ] && strcmp ( _achievement -> name [ i ], buffer ) == 0 )
2012-11-27 13:02:04 +01:00
return true ;
2011-04-27 16:22:42 +06:00
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): linked achievement (id: %u) name wasn't found in any localization" , context , _achievement -> ID );
2012-11-27 13:02:04 +01:00
return false ;
2011-04-27 16:22:42 +06:00
}
// |color|Htrade:spell_id:cur_value:max_value:player_guid:base64_data|h[name]|h|r
// |cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r
bool TradeChatLink :: Initialize ( std :: istringstream & iss )
{
if ( _color != CHAT_LINK_COLOR_TRADE )
return false ;
// Spell Id
uint32 spellId = 0 ;
if ( ! ReadUInt32 ( iss , spellId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate spell
2011-07-26 23:09:28 +02:00
_spell = sSpellMgr -> GetSpellInfo ( spellId );
2011-04-27 16:22:42 +06:00
if ( ! _spell )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command" , iss . str (). c_str (), spellId );
2011-04-27 16:22:42 +06:00
return false ;
}
// Check delimiter
if ( ! CheckDelimiter ( iss , DELIMITER , "trade" ))
return false ;
// Minimum talent level
if ( ! ReadInt32 ( iss , _minSkillLevel ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading minimum talent level" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Check delimiter
if ( ! CheckDelimiter ( iss , DELIMITER , "trade" ))
return false ;
// Maximum talent level
if ( ! ReadInt32 ( iss , _maxSkillLevel ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading maximum talent level" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Check delimiter
if ( ! CheckDelimiter ( iss , DELIMITER , "trade" ))
return false ;
// Something hexadecimal
if ( ! ReadHex ( iss , _guid , 0 ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement's owner guid" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Skip base64 encoded stuff
_base64 = ReadSkip ( iss , PIPE_CHAR );
return true ;
}
// |color|Htalent:talent_id:rank|h[name]|h|r
// |cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r
bool TalentChatLink :: Initialize ( std :: istringstream & iss )
{
if ( _color != CHAT_LINK_COLOR_TALENT )
return false ;
// Read talent entry
if ( ! ReadUInt32 ( iss , _talentId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading talent entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate talent
2011-09-15 14:08:17 +02:00
TalentEntry const * talentInfo = sTalentStore . LookupEntry ( _talentId );
2011-04-27 16:22:42 +06:00
if ( ! talentInfo )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid talent id %u in |talent command" , iss . str (). c_str (), _talentId );
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate talent's spell
2011-07-26 23:09:28 +02:00
_spell = sSpellMgr -> GetSpellInfo ( talentInfo -> RankID [ 0 ]);
2011-04-27 16:22:42 +06:00
if ( ! _spell )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command" , iss . str (). c_str (), talentInfo -> RankID [ 0 ]);
2011-04-27 16:22:42 +06:00
return false ;
}
// Delimiter
if ( ! CheckDelimiter ( iss , DELIMITER , "talent" ))
return false ;
// Rank
if ( ! ReadInt32 ( iss , _rankId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading talent rank" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
return true ;
}
// |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r
// |cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r
bool EnchantmentChatLink :: Initialize ( std :: istringstream & iss )
{
if ( _color != CHAT_LINK_COLOR_ENCHANT )
return false ;
// Spell Id
uint32 spellId = 0 ;
if ( ! ReadUInt32 ( iss , spellId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading enchantment spell entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate spell
2011-07-26 23:09:28 +02:00
_spell = sSpellMgr -> GetSpellInfo ( spellId );
2011-04-27 16:22:42 +06:00
if ( ! _spell )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |enchant command" , iss . str (). c_str (), spellId );
2011-04-27 16:22:42 +06:00
return false ;
}
return true ;
}
// |color|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|h|r
// |cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|h|r
bool GlyphChatLink :: Initialize ( std :: istringstream & iss )
{
if ( _color != CHAT_LINK_COLOR_GLYPH )
return false ;
// Slot
if ( ! ReadUInt32 ( iss , _slotId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading slot id" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Check delimiter
if ( ! CheckDelimiter ( iss , DELIMITER , "glyph" ))
return false ;
// Glyph Id
uint32 glyphId = 0 ;
if ( ! ReadUInt32 ( iss , glyphId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading glyph entry" , iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate glyph
_glyph = sGlyphPropertiesStore . LookupEntry ( glyphId );
if ( ! _glyph )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid glyph id %u in |glyph command" , iss . str (). c_str (), glyphId );
2011-04-27 16:22:42 +06:00
return false ;
}
// Validate glyph's spell
2011-07-26 23:09:28 +02:00
_spell = sSpellMgr -> GetSpellInfo ( _glyph -> SpellId );
2011-04-27 16:22:42 +06:00
if ( ! _spell )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |glyph command" , iss . str (). c_str (), _glyph -> SpellId );
2011-04-27 16:22:42 +06:00
return false ;
}
return true ;
}
2013-10-28 14:36:07 -04:00
LinkExtractor :: LinkExtractor ( const char * msg ) : _iss ( msg ) { }
2011-04-27 16:22:42 +06:00
LinkExtractor ::~ LinkExtractor ()
{
for ( Links :: iterator itr = _links . begin (); itr != _links . end (); ++ itr )
2011-04-27 17:22:55 +02:00
delete * itr ;
2011-04-27 16:22:42 +06:00
_links . clear ();
}
bool LinkExtractor :: IsValidMessage ()
{
const char validSequence [ 6 ] = "cHhhr" ;
const char * validSequenceIterator = validSequence ;
char buffer [ 256 ];
std :: istringstream :: pos_type startPos = 0 ;
uint32 color = 0 ;
ChatLink * link = NULL ;
while ( ! _iss . eof ())
{
if ( validSequence == validSequenceIterator )
{
2011-04-27 17:22:55 +02:00
link = NULL ;
2011-04-27 16:22:42 +06:00
_iss . ignore ( 255 , PIPE_CHAR );
startPos = _iss . tellg () - std :: istringstream :: pos_type ( 1 );
}
else if ( _iss . get () != PIPE_CHAR )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence aborted unexpectedly" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// pipe has always to be followed by at least one char
if ( _iss . peek () == '\0' )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): pipe followed by ' \\ 0'" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
// no further pipe commands
if ( _iss . eof ())
break ;
char commandChar ;
_iss >> commandChar ;
// | in normal messages is escaped by ||
if ( commandChar != PIPE_CHAR )
{
if ( commandChar == * validSequenceIterator )
{
if ( validSequenceIterator == validSequence + 4 )
validSequenceIterator = validSequence ;
else
++ validSequenceIterator ;
}
else
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): invalid sequence, expected '%c' but got '%c'" , _iss . str (). c_str (), * validSequenceIterator , commandChar );
2011-04-27 16:22:42 +06:00
return false ;
}
}
else if ( validSequence != validSequenceIterator )
{
// no escaped pipes in sequences
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got escaped pipe in sequence" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
switch ( commandChar )
{
case 'c' :
if ( ! ReadHex ( _iss , color , 8 ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): invalid hexadecimal number while reading color" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
break ;
case 'H' :
// read chars up to colon = link type
_iss . getline ( buffer , 256 , DELIMITER );
if ( _iss . eof ())
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
if ( strcmp ( buffer , "item" ) == 0 )
link = new ItemChatLink ();
else if ( strcmp ( buffer , "quest" ) == 0 )
link = new QuestChatLink ();
else if ( strcmp ( buffer , "trade" ) == 0 )
link = new TradeChatLink ();
else if ( strcmp ( buffer , "talent" ) == 0 )
link = new TalentChatLink ();
else if ( strcmp ( buffer , "spell" ) == 0 )
link = new SpellChatLink ();
else if ( strcmp ( buffer , "enchant" ) == 0 )
link = new EnchantmentChatLink ();
else if ( strcmp ( buffer , "achievement" ) == 0 )
link = new AchievementChatLink ();
else if ( strcmp ( buffer , "glyph" ) == 0 )
link = new GlyphChatLink ();
else
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): user sent unsupported link type '%s'" , _iss . str (). c_str (), buffer );
2011-04-27 16:22:42 +06:00
return false ;
}
2011-04-27 17:22:55 +02:00
_links . push_back ( link );
2011-04-27 16:22:42 +06:00
link -> SetColor ( color );
if ( ! link -> Initialize ( _iss ))
return false ;
break ;
case 'h' :
// if h is next element in sequence, this one must contain the linked text :)
if ( * validSequenceIterator == 'h' )
{
// links start with '['
if ( _iss . get () != '[' )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): link caption doesn't start with '['" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
_iss . getline ( buffer , 256 , ']' );
if ( _iss . eof ())
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
if ( ! link )
return false ;
if ( ! link -> ValidateName ( buffer , _iss . str (). c_str ()))
return false ;
}
break ;
case 'r' :
if ( link )
link -> SetBounds ( startPos , _iss . tellg ());
case '|' :
// no further payload
break ;
default :
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): got invalid command |%c" , _iss . str (). c_str (), commandChar );
2011-04-27 16:22:42 +06:00
return false ;
}
}
// check if every opened sequence was also closed properly
if ( validSequence != validSequenceIterator )
{
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "chat.system" , "ChatHandler::isValidChatMessage('%s'): EOF in active sequence" , _iss . str (). c_str ());
2011-04-27 16:22:42 +06:00
return false ;
}
return true ;
}