aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Chat/ChatLink.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Chat/ChatLink.cpp')
-rw-r--r--src/server/game/Chat/ChatLink.cpp947
1 files changed, 0 insertions, 947 deletions
diff --git a/src/server/game/Chat/ChatLink.cpp b/src/server/game/Chat/ChatLink.cpp
deleted file mode 100644
index 3e64d71f9f5..00000000000
--- a/src/server/game/Chat/ChatLink.cpp
+++ /dev/null
@@ -1,947 +0,0 @@
-/*
- * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
- *
- * 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 "AchievementMgr.h"
-#include "DB2Stores.h"
-#include "Item.h"
-#include "Log.h"
-#include "ObjectMgr.h"
-#include "QuestDef.h"
-#include "SpellInfo.h"
-#include "SpellMgr.h"
-
-// 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:min_level:max_level:scaling_faction|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
-// |color|Htalent:talent_id, rank|h[name]|h|r - client, talent icon shift-click
-// |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, char const* context)
-{
- char c = iss.peek();
- if (c != delimiter)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid %s link structure ('%c' expected, '%c' found)", iss.str().c_str(), context, delimiter, c);
- 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;
- //uint32 size = uint32(iss.gcount());
- if (length && uint32(iss.tellg() - pos) != length)
- return false;
- return !iss.fail() && !iss.eof();
-}
-
-#define DELIMITER ':'
-#define PIPE_CHAR '|'
-
-bool ChatLink::ValidateName(char* buffer, char const* /*context*/)
-{
- _name = buffer;
- return true;
-}
-
-// |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:random_property:property_seed:reporter_level:reporter_spec:modifiers_mask:context:numBonusListIDs:bonusListIDs(%d):numModifiers:(modifierType(%d):modifierValue(%d)):gem1numBonusListIDs:gem1bonusListIDs(%d):gem2numBonusListIDs:gem2bonusListIDs(%d):gem3numBonusListIDs:gem3bonusListIDs(%d):creator:use_enchant_id|h[name]|h|r
-// |cffa335ee|Hitem:124382:0:0:0:0:0:0:0:0:0:0:0:4:42:562:565:567|h[Edict of Argus]|h|r");
-bool ItemChatLink::Initialize(std::istringstream& iss)
-{
- // Read item entry
- uint32 itemEntry = 0;
- if (!ReadUInt32(iss, itemEntry))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item entry", iss.str().c_str());
- return false;
- }
-
- // Validate item
- _item = sObjectMgr->GetItemTemplate(itemEntry);
- if (!_item)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid itemEntry %u in |item command", iss.str().c_str(), itemEntry);
- return false;
- }
-
- // Validate item's color
- uint32 colorQuality = _item->GetQuality();
- if (_item->GetFlags3() & ITEM_FLAG3_DISPLAY_AS_HEIRLOOM)
- colorQuality = ITEM_QUALITY_HEIRLOOM;
-
- if (_color != ItemQualityColors[colorQuality])
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item has color %u, but user claims %u", iss.str().c_str(), ItemQualityColors[colorQuality], _color);
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _enchantId))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item enchantId", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _gemItemId[0]))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item gem id 1", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _gemItemId[1]))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item gem id 2", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _gemItemId[2]))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item gem id 3", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- int32 zero = 0;
- if (HasValue(iss) && !ReadInt32(iss, zero))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading zero", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, zero))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item random property id", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, zero))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item random property seed", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _reporterLevel))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item owner level", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _reporterSpec))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item owner spec", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- int32 modifiersMask = 0;
- if (HasValue(iss) && !ReadInt32(iss, modifiersMask))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item modifiers mask", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _context))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item context", iss.str().c_str());
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- uint32 numBonusListIDs = 0;
- if (HasValue(iss) && !ReadUInt32(iss, numBonusListIDs))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item bonus lists size", iss.str().c_str());
- return false;
- }
-
- uint32 const maxBonusListIDs = 16;
- if (numBonusListIDs > maxBonusListIDs)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): too many item bonus list IDs %u in |item command", iss.str().c_str(), numBonusListIDs);
- return false;
- }
-
- _bonusListIDs.resize(numBonusListIDs);
- for (uint32 index = 0; index < numBonusListIDs; ++index)
- {
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- int32 id = 0;
- if (!ReadInt32(iss, id))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item bonus list id (index %u)", iss.str().c_str(), index);
- return false;
- }
-
- if (!sDB2Manager.GetItemBonusList(id))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid item bonus list id %d in |item command", iss.str().c_str(), id);
- return false;
- }
-
- _bonusListIDs[index] = id;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- uint32 numModifiers = 0;
- if (HasValue(iss) && !ReadUInt32(iss, numModifiers))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item modifiers size", iss.str().c_str());
- return false;
- }
-
- if (numModifiers > MAX_ITEM_MODIFIERS)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): too many item modifiers %u in |item command", iss.str().c_str(), numBonusListIDs);
- return false;
- }
-
- for (uint32 i = 0; i < numModifiers; ++i)
- {
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- int32 type = 0;
- if (!ReadInt32(iss, type))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item modifier type (index %u)", iss.str().c_str(), i);
- return false;
- }
-
- if (type > MAX_ITEM_MODIFIERS)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid item modifier type %u (index %u)", iss.str().c_str(), type, i);
- return false;
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- int32 id = 0;
- if (!ReadInt32(iss, id))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item modifier value (index %u)", iss.str().c_str(), i);
- return false;
- }
-
- _modifiers.emplace_back(type, id);
- }
-
- for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
- {
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- numBonusListIDs = 0;
- if (HasValue(iss) && !ReadUInt32(iss, numBonusListIDs))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item bonus lists size for gem %u", iss.str().c_str(), i);
- return false;
- }
-
- if (numBonusListIDs > maxBonusListIDs)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): too many item bonus list IDs %u in |item command for gem %u", iss.str().c_str(), numBonusListIDs, i);
- return false;
- }
-
- _gemBonusListIDs[i].resize(numBonusListIDs);
- for (uint32 index = 0; index < numBonusListIDs; ++index)
- {
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- int32 id = 0;
- if (!ReadInt32(iss, id))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item bonus list id (index %u) for gem %u", iss.str().c_str(), index, i);
- return false;
- }
-
- if (!sDB2Manager.GetItemBonusList(id))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid item bonus list id %d in |item command for gem %u", iss.str().c_str(), id, i);
- return false;
- }
-
- _gemBonusListIDs[i][index] = id;
- }
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- // guid as string
- if (HasValue(iss))
- {
- std::array<char, 128> guidBuffer = { };
- if (!iss.getline(guidBuffer.data(), 128, DELIMITER))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading creator guid string", iss.str().c_str());
- return false;
- }
- iss.unget(); // put next : back into stream
- }
-
- if (!CheckDelimiter(iss, DELIMITER, "item"))
- return false;
-
- if (HasValue(iss) && !ReadInt32(iss, _useEnchantId))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading on use enchatment id", iss.str().c_str());
- return false;
- }
-
- return true;
-}
-
-std::string ItemChatLink::FormatName(uint8 index, LocalizedString* suffixStrings) const
-{
- std::stringstream ss;
- ss << _item->GetName(LocaleConstant(index));
-
- if (!(_item->GetFlags3() & ITEM_FLAG3_HIDE_NAME_SUFFIX))
- if (suffixStrings)
- ss << ' ' << suffixStrings->Str[index];
-
- return ss.str();
-}
-
-// item links are compacted to remove all zero values
-bool ItemChatLink::HasValue(std::istringstream& iss) const
-{
- char next = iss.peek();
- return next != DELIMITER && next != PIPE_CHAR;
-}
-
-bool ItemChatLink::ValidateName(char* buffer, char const* context)
-{
- ChatLink::ValidateName(buffer, context);
-
- // TODO: use suffix from ItemNameDescription
- LocalizedString* suffixStrings = nullptr;
-
- for (uint8 locale = LOCALE_enUS; locale < TOTAL_LOCALES; ++locale)
- {
- if (locale == LOCALE_none)
- continue;
-
- if (FormatName(locale, suffixStrings) == buffer)
- return true;
- }
-
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item (id: %u) name wasn't found in any localization", context, _item->GetId());
- return false;
-}
-
-// |color|Hquest:quest_id:quest_level:min_level:max_level:scaling_faction|h[name]|h|r
-// |cffffff00|Hquest:51101:-1:110:120:5|h[The Wounded King]|h|r
-bool QuestChatLink::Initialize(std::istringstream& iss)
-{
- // Read quest id
- uint32 questId = 0;
- if (!ReadUInt32(iss, questId))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest entry", iss.str().c_str());
- return false;
- }
- // Validate quest
- _quest = sObjectMgr->GetQuestTemplate(questId);
- if (!_quest)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): quest template %u not found", iss.str().c_str(), questId);
- return false;
- }
- // Check delimiter
- if (!CheckDelimiter(iss, DELIMITER, "quest"))
- return false;
- // Read quest level
- if (!ReadInt32(iss, _questLevel))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest level", iss.str().c_str());
- return false;
- }
- // Validate quest level
- if (_questLevel >= STRONG_MAX_LEVEL)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): quest level %d is too big", iss.str().c_str(), _questLevel);
- return false;
- }
- if (!ReadInt32(iss, _minLevel))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest min level", iss.str().c_str());
- return false;
- }
- if (!ReadInt32(iss, _maxLevel))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest max level", iss.str().c_str());
- return false;
- }
- if (!ReadInt32(iss, _scalingFaction))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest scaling faction", iss.str().c_str());
- return false;
- }
- return true;
-}
-
-bool QuestChatLink::ValidateName(char* buffer, char const* context)
-{
- ChatLink::ValidateName(buffer, context);
-
- bool res = (_quest->GetLogTitle() == buffer);
- if (!res)
- if (QuestTemplateLocale const* ql = sObjectMgr->GetQuestLocale(_quest->GetQuestId()))
- for (uint8 i = 0; i < ql->LogTitle.size(); i++)
- if (ql->LogTitle[i] == buffer)
- {
- res = true;
- break;
- }
- if (!res)
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked quest (id: %u) title wasn't found in any localization", context, _quest->GetQuestId());
- 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))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading spell entry", iss.str().c_str());
- return false;
- }
- // Validate spell
- _spell = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE);
- if (!_spell)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |spell command", iss.str().c_str(), spellId);
- return false;
- }
- return true;
-}
-
-bool SpellChatLink::ValidateName(char* buffer, char const* context)
-{
- ChatLink::ValidateName(buffer, context);
-
- // spells with that flag have a prefix of "$PROFESSION: "
- if (_spell->HasAttribute(SPELL_ATTR0_TRADESPELL))
- {
- SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(_spell->Id);
- if (bounds.first == bounds.second)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line not found for spell %u", context, _spell->Id);
- return false;
- }
- SkillLineAbilityEntry const* skillInfo = bounds.first->second;
- if (!skillInfo)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line ability not found for spell %u", context, _spell->Id);
- return false;
- }
- SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillInfo->SkillLine);
- if (!skillLine)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line not found for skill %u", context, skillInfo->SkillLine);
- return false;
- }
-
- for (LocaleConstant i = LOCALE_enUS; i < TOTAL_LOCALES; i = LocaleConstant(i + 1))
- {
- uint32 skillLineNameLength = strlen(skillLine->DisplayName[i]);
- if (skillLineNameLength > 0 && strncmp(skillLine->DisplayName[i], buffer, skillLineNameLength) == 0)
- {
- // found the prefix, remove it to perform spellname validation below
- // -2 = strlen(": ")
- uint32 spellNameLength = strlen(buffer) - skillLineNameLength - 2;
- memmove(buffer, buffer + skillLineNameLength + 2, spellNameLength + 1);
- break;
- }
- }
- }
-
- for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
- if (*_spell->SpellName->Str[i] && strcmp(_spell->SpellName->Str[i], buffer) == 0)
- return true;
-
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked spell (id: %u) name wasn't found in any localization", context, _spell->Id);
- return false;
-}
-
-// |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))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement entry", iss.str().c_str());
- return false;
- }
- // Validate achievement
- _achievement = sAchievementStore.LookupEntry(achievementId);
- if (!_achievement)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid achivement id %u in |achievement command", iss.str().c_str(), achievementId);
- return false;
- }
- // Check delimiter
- if (!CheckDelimiter(iss, DELIMITER, "achievement"))
- return false;
- // Read HEX
- if (!ReadHex(iss, _guid, 0))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid hexadecimal number while reading char's guid", iss.str().c_str());
- 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]))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement property (%u)", iss.str().c_str(), index);
- return false;
- }
- }
- return true;
-}
-
-bool AchievementChatLink::ValidateName(char* buffer, char const* context)
-{
- ChatLink::ValidateName(buffer, context);
-
- for (LocaleConstant locale = LOCALE_enUS; locale < TOTAL_LOCALES; locale = LocaleConstant(locale + 1))
- {
- if (locale == LOCALE_none)
- continue;
-
- if (strcmp(_achievement->Title[locale], buffer) == 0)
- return true;
- }
-
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked achievement (id: %u) name wasn't found in any localization", context, _achievement->ID);
- return false;
-}
-
-// |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))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement entry", iss.str().c_str());
- return false;
- }
- // Validate spell
- _spell = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE);
- if (!_spell)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), spellId);
- return false;
- }
- // Check delimiter
- if (!CheckDelimiter(iss, DELIMITER, "trade"))
- return false;
- // Minimum talent level
- if (!ReadInt32(iss, _minSkillLevel))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading minimum talent level", iss.str().c_str());
- return false;
- }
- // Check delimiter
- if (!CheckDelimiter(iss, DELIMITER, "trade"))
- return false;
- // Maximum talent level
- if (!ReadInt32(iss, _maxSkillLevel))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading maximum talent level", iss.str().c_str());
- return false;
- }
- // Check delimiter
- if (!CheckDelimiter(iss, DELIMITER, "trade"))
- return false;
- // Something hexadecimal
- if (!ReadHex(iss, _guid, 0))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement's owner guid", iss.str().c_str());
- 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))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading talent entry", iss.str().c_str());
- return false;
- }
- // Validate talent
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(_talentId);
- if (!talentInfo)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid talent id %u in |talent command", iss.str().c_str(), _talentId);
- return false;
- }
- // Validate talent's spell
- _spell = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE);
- if (!_spell)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), talentInfo->SpellID);
- return false;
- }
- // Delimiter
- if (!CheckDelimiter(iss, DELIMITER, "talent"))
- return false;
- // Rank
- if (!ReadInt32(iss, _rankId))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading talent rank", iss.str().c_str());
- 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))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading enchantment spell entry", iss.str().c_str());
- return false;
- }
- // Validate spell
- _spell = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE);
- if (!_spell)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |enchant command", iss.str().c_str(), spellId);
- 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))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading slot id", iss.str().c_str());
- return false;
- }
- // Check delimiter
- if (!CheckDelimiter(iss, DELIMITER, "glyph"))
- return false;
- // Glyph Id
- uint32 glyphId = 0;
- if (!ReadUInt32(iss, glyphId))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading glyph entry", iss.str().c_str());
- return false;
- }
- // Validate glyph
- _glyph = sGlyphPropertiesStore.LookupEntry(glyphId);
- if (!_glyph)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid glyph id %u in |glyph command", iss.str().c_str(), glyphId);
- return false;
- }
- // Validate glyph's spell
- _spell = sSpellMgr->GetSpellInfo(_glyph->SpellID, DIFFICULTY_NONE);
- if (!_spell)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |glyph command", iss.str().c_str(), _glyph->SpellID);
- return false;
- }
- return true;
-}
-
-LinkExtractor::LinkExtractor(char const* msg) : _iss(msg) { }
-
-LinkExtractor::~LinkExtractor()
-{
- for (Links::iterator itr = _links.begin(); itr != _links.end(); ++itr)
- delete *itr;
- _links.clear();
-}
-
-bool LinkExtractor::IsValidMessage()
-{
- const char validSequence[6] = "cHhhr";
- char const* validSequenceIterator = validSequence;
-
- char buffer[256];
-
- std::istringstream::pos_type startPos = 0;
- uint32 color = 0;
-
- ChatLink* link = nullptr;
- while (!_iss.eof())
- {
- if (validSequence == validSequenceIterator)
- {
- link = nullptr;
- _iss.ignore(255, PIPE_CHAR);
- startPos = _iss.tellg() - std::istringstream::pos_type(1);
- }
- else if (_iss.get() != PIPE_CHAR)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence aborted unexpectedly", _iss.str().c_str());
- return false;
- }
-
- // pipe has always to be followed by at least one char
- if (_iss.peek() == '\0')
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): pipe followed by '\\0'", _iss.str().c_str());
- return false;
- }
-
- // no further pipe commands
- if (_iss.eof())
- break;
-
- char commandChar;
- _iss.get(commandChar);
-
- // | in normal messages is escaped by ||
- if (commandChar != PIPE_CHAR)
- {
- if (commandChar == *validSequenceIterator)
- {
- if (validSequenceIterator == validSequence+4)
- validSequenceIterator = validSequence;
- else
- ++validSequenceIterator;
- }
- else
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid sequence, expected '%c' but got '%c'", _iss.str().c_str(), *validSequenceIterator, commandChar);
- return false;
- }
- }
- else if (validSequence != validSequenceIterator)
- {
- // no escaped pipes in sequences
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got escaped pipe in sequence", _iss.str().c_str());
- return false;
- }
-
- switch (commandChar)
- {
- case 'c':
- if (!ReadHex(_iss, color, 8))
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid hexadecimal number while reading color", _iss.str().c_str());
- return false;
- }
- break;
- case 'H':
- // read chars up to colon = link type
- _iss.getline(buffer, 256, DELIMITER);
- if (_iss.eof())
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", _iss.str().c_str());
- 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
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): user sent unsupported link type '%s'", _iss.str().c_str(), buffer);
- return false;
- }
- _links.push_back(link);
- 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() != '[')
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): link caption doesn't start with '['", _iss.str().c_str());
- return false;
- }
- _iss.getline(buffer, 256, ']');
- if (_iss.eof())
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", _iss.str().c_str());
- 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:
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid command |%c", _iss.str().c_str(), commandChar);
- return false;
- }
- }
-
- // check if every opened sequence was also closed properly
- if (validSequence != validSequenceIterator)
- {
- TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): EOF in active sequence", _iss.str().c_str());
- return false;
- }
-
- return true;
-}