diff options
author | megamage <none@none> | 2009-08-27 19:57:35 -0500 |
---|---|---|
committer | megamage <none@none> | 2009-08-27 19:57:35 -0500 |
commit | 90b55ff7b15bb243fce40ec733630bc605bf04a9 (patch) | |
tree | b0381baf2443edf45173b1fb9e77c6f6b12f05ff /src/game | |
parent | 82bd15b7beb92d57e3925781581d62425d675398 (diff) |
[8424] Added support for strict chatmessage validation Author: arrai
--HG--
branch : trunk
Diffstat (limited to 'src/game')
-rw-r--r-- | src/game/Chat.cpp | 537 | ||||
-rw-r--r-- | src/game/Chat.h | 2 | ||||
-rw-r--r-- | src/game/ChatHandler.cpp | 77 | ||||
-rw-r--r-- | src/game/DBCStructure.h | 2 | ||||
-rw-r--r-- | src/game/DBCfmt.h | 2 | ||||
-rw-r--r-- | src/game/LootMgr.cpp | 2 | ||||
-rw-r--r-- | src/game/SharedDefines.h | 24 | ||||
-rw-r--r-- | src/game/Unit.cpp | 2 | ||||
-rw-r--r-- | src/game/World.cpp | 2 | ||||
-rw-r--r-- | src/game/World.h | 2 | ||||
-rw-r--r-- | src/game/WorldSession.h | 1 |
11 files changed, 615 insertions, 38 deletions
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index a06bcf27fdd..6e391cca247 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -34,6 +34,7 @@ #include "Opcodes.h" #include "Player.h" #include "UpdateMask.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 @@ -1077,6 +1078,542 @@ int ChatHandler::ParseCommands(const char* text) return 1; } +bool ChatHandler::isValidChatMessage(const char* message) +{ +/* + +valid examples: +|cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r +|cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r +|cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r +|cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r +|cff71d5ff|Hspell:21563|h[Command]|h|r +|cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r +|cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r +|cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|h|r + +| will be escaped to || +*/ + + if(strlen(message) > 255) + return false; + + const char validSequence[6] = "cHhhr"; + const char* validSequenceIterator = validSequence; + + // more simple checks + if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) < 3) + { + const std::string validCommands = "cHhr|"; + + while(*message) + { + // find next pipe command + message = strchr(message, '|'); + + if(!message) + return true; + + ++message; + char commandChar = *message; + if(validCommands.find(commandChar) == std::string::npos) + return false; + + ++message; + // validate sequence + if(sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) == 2) + { + if(commandChar == *validSequenceIterator) + { + if (validSequenceIterator == validSequence+4) + validSequenceIterator = validSequence; + else + ++validSequenceIterator; + } + else + return false; + } + } + return true; + } + + std::istringstream reader(message); + char buffer[256]; + + uint32 color; + + ItemPrototype const* linkedItem; + Quest const* linkedQuest; + SpellEntry const *linkedSpell; + AchievementEntry const* linkedAchievement; + + while(!reader.eof()) + { + if (validSequence == validSequenceIterator) + { + linkedItem = NULL; + linkedQuest = NULL; + linkedSpell = NULL; + linkedAchievement = NULL; + + reader.ignore(255, '|'); + } + else if(reader.get() != '|') + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage sequence aborted unexpectedly"); +#endif + return false; + } + + // pipe has always to be followed by at least one char + if ( reader.peek() == '\0') + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage pipe followed by \\0"); +#endif + return false; + } + + // no further pipe commands + if (reader.eof()) + break; + + char commandChar; + reader >> commandChar; + + // | in normal messages is escaped by || + if (commandChar != '|') + { + if(commandChar == *validSequenceIterator) + { + if (validSequenceIterator == validSequence+4) + validSequenceIterator = validSequence; + else + ++validSequenceIterator; + } + else + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage invalid sequence, expected %c but got %c", *validSequenceIterator, commandChar); +#endif + return false; + } + } + else if(validSequence != validSequenceIterator) + { + // no escaped pipes in sequences +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage got escaped pipe in sequence"); +#endif + return false; + } + + switch (commandChar) + { + case 'c': + color = 0; + // validate color, expect 8 hex chars + for(int i=0; i<8; i++) + { + char c; + reader >> c; + if(!c) + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage got \\0 while reading color in |c command"); +#endif + return false; + } + + color <<= 4; + // check for hex char + if(c >= '0' && c <='9') + { + color |= c-'0'; + continue; + } + if(c >= 'a' && c <='f') + { + color |= 10+c-'a'; + continue; + } +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage got non hex char '%c' while reading color", c); +#endif + return false; + } + break; + case 'H': + // read chars up to colon = link type + reader.getline(buffer, 256, ':'); + + if (strcmp(buffer, "item") == 0) + { + // read item entry + reader.getline(buffer, 256, ':'); + + linkedItem= objmgr.GetItemPrototype(atoi(buffer)); + if(!linkedItem) + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage got invalid itemID %u in |item command", atoi(buffer)); +#endif + return false; + } + + if (color != ItemQualityColors[linkedItem->Quality]) + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage linked item has color %u, but user claims %u", ItemQualityColors[linkedItem->Quality], + color); +#endif + return false; + } + + char c = reader.peek(); + + // ignore enchants etc. + while(c >='0' && c <='9' || c==':') + { + reader.ignore(1); + c = reader.peek(); + } + } + else if(strcmp(buffer, "quest") == 0) + { + // no color check for questlinks, each client will adapt it anyway + uint32 questid= 0; + // read questid + char c = reader.peek(); + while(c >='0' && c<='9') + { + reader.ignore(1); + questid *= 10; + questid += c-'0'; + c = reader.peek(); + } + + linkedQuest = objmgr.GetQuestTemplate(questid); + + if(!linkedQuest) + { +#ifdef MANOGS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage Questtemplate %u not found", questid); +#endif + return false; + } + c = reader.peek(); + // level + while(c !='|' && c!='\0') + { + reader.ignore(1); + c = reader.peek(); + } + } + else if(strcmp(buffer, "trade") == 0) + { + if(color != CHAT_LINK_COLOR_TRADE) + return false; + + // read spell entry + reader.getline(buffer, 256, ':'); + linkedSpell = sSpellStore.LookupEntry(atoi(buffer)); + if(!linkedSpell) + return false; + + char c = reader.peek(); + // base64 encoded stuff + while(c !='|' && c!='\0') + { + reader.ignore(1); + c = reader.peek(); + } + } + else if(strcmp(buffer, "talent") == 0) + { + // talent links are always supposed to be blue + if(color != CHAT_LINK_COLOR_TALENT) + return false; + + // read talent entry + reader.getline(buffer, 256, ':'); + TalentEntry const *talentInfo = sTalentStore.LookupEntry(atoi(buffer)); + if(!talentInfo) + return false; + + linkedSpell = sSpellStore.LookupEntry(talentInfo->RankID[0]); + if(!linkedSpell) + return false; + + char c = reader.peek(); + // skillpoints? whatever, drop it + while(c !='|' && c!='\0') + { + reader.ignore(1); + c = reader.peek(); + } + } + else if(strcmp(buffer, "spell") == 0) + { + if(color != CHAT_LINK_COLOR_SPELL) + return false; + + uint32 spellid = 0; + // read spell entry + char c = reader.peek(); + while(c >='0' && c<='9') + { + reader.ignore(1); + spellid *= 10; + spellid += c-'0'; + c = reader.peek(); + } + linkedSpell = sSpellStore.LookupEntry(spellid); + if(!linkedSpell) + return false; + } + else if(strcmp(buffer, "enchant") == 0) + { + if(color != CHAT_LINK_COLOR_ENCHANT) + return false; + + uint32 spellid = 0; + // read spell entry + char c = reader.peek(); + while(c >='0' && c<='9') + { + reader.ignore(1); + spellid *= 10; + spellid += c-'0'; + c = reader.peek(); + } + linkedSpell = sSpellStore.LookupEntry(spellid); + if(!linkedSpell) + return false; + } + else if(strcmp(buffer, "achievement") == 0) + { + if(color != CHAT_LINK_COLOR_ACHIEVEMENT) + return false; + reader.getline(buffer, 256, ':'); + uint32 achievementId = atoi(buffer); + linkedAchievement = sAchievementStore.LookupEntry(achievementId); + + if(!linkedAchievement) + return false; + + char c = reader.peek(); + // skip progress + while(c !='|' && c!='\0') + { + reader.ignore(1); + c = reader.peek(); + } + } + else if(strcmp(buffer, "glyph") == 0) + { + if(color != CHAT_LINK_COLOR_GLYPH) + return false; + + // first id is slot, drop it + reader.getline(buffer, 256, ':'); + uint32 glyphId = 0; + char c = reader.peek(); + while(c>='0' && c <='9') + { + glyphId *= 10; + glyphId += c-'0'; + reader.ignore(1); + c = reader.peek(); + } + GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId); + if(!glyph) + return false; + + linkedSpell = sSpellStore.LookupEntry(glyph->SpellId); + + if(!linkedSpell) + return false; + } + else + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage user sent unsupported link type '%s'", buffer); +#endif + 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(reader.get() != '[') + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage link caption doesn't start with '['"); +#endif + return false; + } + reader.getline(buffer, 256, ']'); + + // verify the link name + if (linkedSpell) + { + // spells with that flag have a prefix of "$PROFESSION: " + if(linkedSpell->Attributes & SPELL_ATTR_TRADESPELL) + { + // lookup skillid + SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(linkedSpell->Id); + SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(linkedSpell->Id); + + if(lower == upper) + { + return false; + } + + SkillLineAbilityEntry const *skillInfo = lower->second; + + if (!skillInfo) + { + return false; + } + + SkillLineEntry const *skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId); + if(!skillLine) + { + return false; + } + + for(uint8 i=0; i<MAX_LOCALE; ++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; + memmove(buffer, buffer+skillLineNameLength+2, spellNameLength+1); + } + } + } + bool foundName = false; + for(uint8 i=0; i<MAX_LOCALE; ++i) + { + if(*linkedSpell->SpellName[i] && strcmp(linkedSpell->SpellName[i], buffer) == 0) + { + foundName = true; + break; + } + } + if(!foundName) + return false; + } + else if(linkedQuest) + { + if (linkedQuest->GetTitle() != buffer) + { + QuestLocale const *ql = objmgr.GetQuestLocale(linkedQuest->GetQuestId()); + + if(!ql) + { +#ifdef MANOGS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage default questname didn't match and there is no locale"); +#endif + return false; + } + + bool foundName = false; + for(uint8 i=0; i<ql->Title.size(); i++) + { + if(ql->Title[i] == buffer) + { + foundName = true; + break; + } + } + if(!foundName) + { +#ifdef MANOGS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage no quest locale title matched") +#endif + return false; + } + } + } + else if(linkedItem) + { + if(strcmp(linkedItem->Name1, buffer) != 0) + { + ItemLocale const *il = objmgr.GetItemLocale(linkedItem->ItemId); + + if(!il) + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage linked item name doesn't is wrong and there is no localization"); +#endif + return false; + } + + bool foundName = false; + for(uint8 i=0; i<il->Name.size(); ++i) + { + if(il->Name[i] == buffer) + { + foundName = true; + break; + } + } + if(!foundName) + { +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage linked item name wasn't found in any localization"); +#endif + return false; + } + } + } + else if(linkedAchievement) + { + bool foundName = false; + for(uint8 i=0; i<MAX_LOCALE; ++i) + { + if(*linkedAchievement->name[i], strcmp(linkedAchievement->name[i], buffer) == 0) + { + foundName = true; + break; + } + } + if(!foundName) + return false; + } + // that place should never be reached - if nothing linked has been set in |H + // it will return false before + else + return false; + } + break; + case 'r': + case '|': + // no further payload + break; + default: +#ifdef MANGOS_DEBUG + sLog.outBasic("ChatHandler::isValidChatMessage got invalid command |%c", commandChar); +#endif + return false; + } + } + + // check if every opened sequence was also closed properly +#ifdef MANGOS_DEBUG + if(validSequence != validSequenceIterator) + sLog.outBasic("ChatHandler::isValidChatMessage EOF in active sequence"); +#endif + return validSequence == validSequenceIterator; +} + bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd) { std::string list; diff --git a/src/game/Chat.h b/src/game/Chat.h index 308698fc04f..f7b948c2cea 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -74,6 +74,8 @@ class ChatHandler int ParseCommands(const char* text); static ChatCommand* getCommandTable(); + + bool isValidChatMessage(const char* msg); protected: explicit ChatHandler() : m_session(NULL) {} // for CLI subclass diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 106e445c245..082a4a6beac 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -40,6 +40,28 @@ #include "SpellAuras.h" #include "Util.h" +bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang) +{ + if (lang != LANG_ADDON) + { + // strip invisible characters for non-addon messages + if(sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) + stripLineInvisibleChars(msg); + + if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && GetSecurity() < SEC_MODERATOR + && !ChatHandler(this).isValidChatMessage(msg.c_str())) + { + sLog.outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(), + GetPlayer()->GetGUIDLow(), msg.c_str()); + if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) + KickPlayer(); + return false; + } + } + + return true; +} + void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) { uint32 type; @@ -177,9 +199,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) break; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -198,9 +219,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) recv_data >> to; recv_data >> msg; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -257,9 +277,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) break; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -290,9 +309,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) break; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -328,9 +346,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) break; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -358,9 +375,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) break; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -390,9 +406,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) break; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -415,9 +430,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) std::string msg=""; recv_data >> msg; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -441,9 +455,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) std::string msg=""; recv_data >> msg; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -467,9 +480,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) std::string msg=""; recv_data >> msg; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; @@ -495,9 +507,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) recv_data >> msg; - // strip invisible characters for non-addon messages - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; if(msg.empty()) break; diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index ca903346815..c0af3a9be00 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -44,7 +44,7 @@ struct AchievementEntry uint32 factionFlag; // 1 -1=all, 0=horde, 1=alliance uint32 mapID; // 2 -1=none //uint32 parentAchievement; // 3 its Achievement parent (can`t start while parent uncomplete, use its Criteria if don`t have own, use its progress on begin) - //char *name[16]; // 4-19 + char *name[16]; // 4-19 //uint32 name_flags; // 20 //char *description[16]; // 21-36 //uint32 desc_flags; // 37 diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h index 91fc4e5cc01..290514872f9 100644 --- a/src/game/DBCfmt.h +++ b/src/game/DBCfmt.h @@ -21,7 +21,7 @@ #ifndef MANGOS_DBCSFRM_H #define MANGOS_DBCSFRM_H -const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii"; +const char Achievementfmt[]="niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii"; const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix"; const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx"; const char AreaGroupEntryfmt[]="niiiiiii"; diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index b54d7b90774..df11d909dd0 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -1325,7 +1325,7 @@ void LoadLootTemplates_Spell() { // not report about not trainable spells (optionally supported by DB) // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example - if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_UNK5)) + if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_TRADESPELL)) { LootTemplates_Spell.ReportNotExistedId(spell_id); } diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 11108cedf80..e03239332c4 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -215,6 +215,18 @@ enum SpellCategory SPELL_CATEGORY_DRINK = 59, }; +const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = { + 0xff9d9d9d, //GREY + 0xffffffff, //WHITE + 0xff1eff00, //GREEN + 0xff0070dd, //BLUE + 0xffa335ee, //PURPLE + 0xffff8000, //ORANGE + 0xffe6cc80, //LIGHT YELLOW + 0xffe6cc80 //LIGHT YELLOW +}; + + // *********************************** // Spell Attributes definitions // *********************************** @@ -224,7 +236,7 @@ enum SpellCategory #define SPELL_ATTR_ON_NEXT_SWING 0x00000004 // 2 on next swing #define SPELL_ATTR_UNK3 0x00000008 // 3 not set in 3.0.3 #define SPELL_ATTR_UNK4 0x00000010 // 4 -#define SPELL_ATTR_UNK5 0x00000020 // 5 trade spells? +#define SPELL_ATTR_TRADESPELL 0x00000020 // 5 trade spells, will be added by client to a sublist of profession spell #define SPELL_ATTR_PASSIVE 0x00000040 // 6 Passive spell #define SPELL_ATTR_UNK7 0x00000080 // 7 visible? #define SPELL_ATTR_UNK8 0x00000100 // 8 @@ -2398,6 +2410,16 @@ enum ChatMsg #define MAX_CHAT_MSG_TYPE 0x32 +enum ChatLinkColors +{ + CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange + CHAT_LINK_COLOR_TALENT = 0xff4e96f7, // blue + CHAT_LINK_COLOR_SPELL = 0xff71d5ff, // bright blue + CHAT_LINK_COLOR_ENCHANT = 0xffffd000, // orange + CHAT_LINK_COLOR_ACHIEVEMENT = 0xffffff00, + CHAT_LINK_COLOR_GLYPH = 0xff66bbff +}; + // Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.petDietMask enum PetDiet { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index b19c88ba376..dc404b40abf 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -11563,7 +11563,7 @@ void Unit::ModSpellCastTime(SpellEntry const* spellProto, int32 & castTime, Spel if(Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CASTING_TIME, castTime, spell); - if( !(spellProto->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) && spellProto->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spellProto->SpellFamilyName) + if( !(spellProto->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_TRADESPELL)) && spellProto->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spellProto->SpellFamilyName) castTime = int32( float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED)); else { diff --git a/src/game/World.cpp b/src/game/World.cpp index ecc90e2ced0..22cfebf8911 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -977,6 +977,8 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true); m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false); + m_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY] = sConfig.GetIntDefault("ChatStrictLinkChecking.Severity", 0); + m_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_KICK] = sConfig.GetIntDefault("ChatStrictLinkChecking.Kick", 0); m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60); m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300); diff --git a/src/game/World.h b/src/game/World.h index 1a7eded0535..e78bd35e10a 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -188,6 +188,8 @@ enum WorldConfigs CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL, CONFIG_TALENTS_INSPECTING, CONFIG_CHAT_FAKE_MESSAGE_PREVENTING, + CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY, + CONFIG_CHAT_STRICT_LINK_CHECKING_KICK, CONFIG_CORPSE_DECAY_NORMAL, CONFIG_CORPSE_DECAY_RARE, CONFIG_CORPSE_DECAY_ELITE, diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 27c0c3e472d..c549a2c87ad 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -552,6 +552,7 @@ class TRINITY_DLL_SPEC WorldSession void HandlePushQuestToParty(WorldPacket& recvPacket); void HandleQuestPushResult(WorldPacket& recvPacket); + bool processChatmessageFurtherAfterSecurityChecks(std::string&, uint32); void HandleMessagechatOpcode(WorldPacket& recvPacket); void HandleTextEmoteOpcode(WorldPacket& recvPacket); void HandleChatIgnoredOpcode(WorldPacket& recvPacket); |