diff options
-rwxr-xr-x | src/server/game/Chat/Chat.cpp | 323 | ||||
-rwxr-xr-x | src/server/game/Chat/Chat.h | 1 |
2 files changed, 184 insertions, 140 deletions
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index bd418bca668..b22e27a7693 100755 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -35,6 +35,13 @@ #include "SpellMgr.h" #include "ScriptMgr.h" +#ifdef TRINITY_DEBUG + #define LOG(...) sLog->outDebug(LOG_FILTER_CHATSYS, __VA_ARGS__); +#else + #define LOG(...) +#endif + + // 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 @@ -57,7 +64,7 @@ // |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 +// |color|Htrade:spell_id:cur_value:max_value:unk3int:unk3str|h[name]|h|r - client, spellbook profession icon shift-click bool ChatHandler::load_command_table = true; @@ -832,6 +839,20 @@ int ChatHandler::ParseCommands(const char* text) return 1; } +inline uint32 ChatHandler::_ReadUInt32(std::istringstream& reader) const +{ + uint32 res = 0; + char c = reader.peek(); + while (c >='0' && c <= '9') + { + reader.ignore(1); + res *= 10; + res += c-'0'; + c = reader.peek(); + } + return res; +} + bool ChatHandler::isValidChatMessage(const char* message) { /* @@ -918,18 +939,14 @@ valid examples: } else if (reader.get() != '|') { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage sequence aborted unexpectedly"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): sequence aborted unexpectedly", reader.str().c_str()); return false; } // pipe has always to be followed by at least one char if (reader.peek() == '\0') { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage pipe followed by \\0"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): pipe followed by '\\0'", reader.str().c_str()); return false; } @@ -952,18 +969,14 @@ valid examples: } else { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage invalid sequence, expected %c but got %c", *validSequenceIterator, commandChar); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): invalid sequence, expected '%c' but got '%c'", reader.str().c_str(), *validSequenceIterator, commandChar); return false; } } else if (validSequence != validSequenceIterator) { // no escaped pipes in sequences -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage got escaped pipe in sequence"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): got escaped pipe in sequence", reader.str().c_str()); return false; } @@ -972,60 +985,59 @@ valid examples: case 'c': color = 0; // validate color, expect 8 hex chars - for (int i=0; i<8; i++) + for (uint8 i = 0; i < 8; ++i) { char c; reader >> c; if (!c) { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage got \\0 while reading color in |c command"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): got \\0 while reading color in |c command", reader.str().c_str()); return false; } color <<= 4; // check for hex char if (c >= '0' && c <= '9') + color |= c - '0'; + else if (c >= 'a' && c <= 'f') + color |= 10 + c - 'a'; + else { - color |= c-'0'; - continue; - } - if (c >= 'a' && c <= 'f') - { - color |= 10+c-'a'; - continue; + LOG("ChatHandler::isValidChatMessage('%s'): got non hex char '%c' while reading color", reader.str().c_str(), c); + return false; } -#ifdef TRINITY_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 (reader.eof()) + { + LOG("ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", reader.str().c_str()); + return false; + } if (strcmp(buffer, "item") == 0) { // read item entry reader.getline(buffer, 256, ':'); + if (reader.eof()) + { + LOG("ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", reader.str().c_str()); + return false; + } - linkedItem= ObjectMgr::GetItemPrototype(atoi(buffer)); + uint32 itemEntry = atoi(buffer); + linkedItem = ObjectMgr::GetItemPrototype(itemEntry); if (!linkedItem) { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage got invalid itemID %u in |item command", atoi(buffer)); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): got invalid itemEntry %u in |item command", reader.str().c_str(), itemEntry); return false; } if (color != ItemQualityColors[linkedItem->Quality]) { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage linked item has color %u, but user claims %u", ItemQualityColors[linkedItem->Quality], - color); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): linked item has color %u, but user claims %u", reader.str().c_str(), ItemQualityColors[linkedItem->Quality], color); return false; } @@ -1045,29 +1057,39 @@ valid examples: { if (c >='0' && c <= '9') { - propertyId*=10; - propertyId += c-'0'; - } else if (c == '-') + propertyId *= 10; + propertyId += c - '0'; + } + else if (c == '-') negativeNumber = true; else + { + LOG("ChatHandler::isValidChatMessage('%s'): invalid character '%c' found while reading item properties", reader.str().c_str(), c); return false; + } } - } - if (negativeNumber) - propertyId *= -1; + if (negativeNumber) + propertyId = -propertyId; - if (propertyId > 0) - { - itemProperty = sItemRandomPropertiesStore.LookupEntry(propertyId); - if (!itemProperty) - return false; - } - else if (propertyId < 0) - { - itemSuffix = sItemRandomSuffixStore.LookupEntry(-propertyId); - if (!itemSuffix) - return false; + if (propertyId > 0) + { + itemProperty = sItemRandomPropertiesStore.LookupEntry(propertyId); + if (!itemProperty) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid item property id %u in |item command", reader.str().c_str(), propertyId); + return false; + } + } + else if (propertyId < 0) + { + itemSuffix = sItemRandomSuffixStore.LookupEntry(-propertyId); + if (!itemSuffix) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid item suffix id %u in |item command", reader.str().c_str(), -propertyId); + return false; + } + } } // ignore other integers @@ -1079,33 +1101,28 @@ valid examples: } 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') + // Quest Id + uint32 questId = _ReadUInt32(reader); + linkedQuest = sObjectMgr->GetQuestTemplate(questId); + if (!linkedQuest) { - reader.ignore(1); - questid *= 10; - questid += c-'0'; - c = reader.peek(); + LOG("ChatHandler::isValidChatMessage('%s'): quest template %u not found", reader.str().c_str(), questId); + return false; } - - linkedQuest = sObjectMgr->GetQuestTemplate(questid); - - if (!linkedQuest) + // Delimiter + char c = reader.peek(); + if (c != ':') { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage Questtemplate %u not found", questid); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): invalid quest link structure (':' expected, '%c' found)", reader.str().c_str(), c); return false; } - c = reader.peek(); - // level - while (c !='|' && c != '\0') + reader.ignore(1); + // Quest level + uint32 questLevel = _ReadUInt32(reader); + if (questLevel >= STRONG_MAX_LEVEL) { - reader.ignore(1); - c = reader.peek(); + LOG("ChatHandler::isValidChatMessage('%s'): quest level %u is too big", reader.str().c_str(), questLevel); + return false; } } else if (strcmp(buffer, "trade") == 0) @@ -1113,15 +1130,25 @@ valid examples: if (color != CHAT_LINK_COLOR_TRADE) return false; - // read spell entry + // Spell Id reader.getline(buffer, 256, ':'); - linkedSpell = sSpellStore.LookupEntry(atoi(buffer)); + if (reader.eof()) + { + LOG("ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", reader.str().c_str()); + return false; + } + + uint32 spellId = atoi(buffer); + linkedSpell = sSpellStore.LookupEntry(spellId); if (!linkedSpell) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", reader.str().c_str(), spellId); return false; + } - char c = reader.peek(); // base64 encoded stuff - while (c !='|' && c != '\0') + char c = reader.peek(); + while (c != '|' && c != '\0') { reader.ignore(1); c = reader.peek(); @@ -1135,17 +1162,30 @@ valid examples: // read talent entry reader.getline(buffer, 256, ':'); - TalentEntry const *talentInfo = sTalentStore.LookupEntry(atoi(buffer)); + if (reader.eof()) + { + LOG("ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", reader.str().c_str()); + return false; + } + + uint32 talentId = atoi(buffer); + TalentEntry const *talentInfo = sTalentStore.LookupEntry(talentId); if (!talentInfo) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid talent id %u in |talent command", reader.str().c_str(), talentId); return false; + } linkedSpell = sSpellStore.LookupEntry(talentInfo->RankID[0]); if (!linkedSpell) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", reader.str().c_str(), talentInfo->RankID[0]); return false; + } - char c = reader.peek(); // skillpoints? whatever, drop it - while (c !='|' && c != '\0') + char c = reader.peek(); + while (c != '|' && c != '\0') { reader.ignore(1); c = reader.peek(); @@ -1156,52 +1196,52 @@ valid examples: 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); + // Spell Id + uint32 spellId = _ReadUInt32(reader); + linkedSpell = sSpellStore.LookupEntry(spellId); if (!linkedSpell) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |spell command", reader.str().c_str(), spellId); 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); + // Spell Id + uint32 spellId = _ReadUInt32(reader); + linkedSpell = sSpellStore.LookupEntry(spellId); if (!linkedSpell) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |enchant command", reader.str().c_str(), spellId); return false; + } } else if (strcmp(buffer, "achievement") == 0) { if (color != CHAT_LINK_COLOR_ACHIEVEMENT) return false; + + // Achievemnt Id reader.getline(buffer, 256, ':'); + if (reader.eof()) + { + LOG("ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", reader.str().c_str()); + return false; + } + uint32 achievementId = atoi(buffer); linkedAchievement = sAchievementStore.LookupEntry(achievementId); - if (!linkedAchievement) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid achivement id %u in |achievement command", reader.str().c_str(), achievementId); return false; + } - char c = reader.peek(); // skip progress + char c = reader.peek(); while (c !='|' && c != '\0') { reader.ignore(1); @@ -1215,29 +1255,30 @@ valid examples: // first id is slot, drop it reader.getline(buffer, 256, ':'); - uint32 glyphId = 0; - char c = reader.peek(); - while (c >= '0' && c <= '9') + if (reader.eof()) { - glyphId *= 10; - glyphId += c-'0'; - reader.ignore(1); - c = reader.peek(); + LOG("ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", reader.str().c_str()); + return false; } + + uint32 glyphId = _ReadUInt32(reader); GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId); if (!glyph) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid glyph id %u in |glyph command", reader.str().c_str(), glyphId); return false; + } linkedSpell = sSpellStore.LookupEntry(glyph->SpellId); - if (!linkedSpell) + { + LOG("ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |glyph command", reader.str().c_str(), glyph->SpellId); return false; + } } else { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage user sent unsupported link type '%s'", buffer); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): user sent unsupported link type '%s'", reader.str().c_str(), buffer); return false; } break; @@ -1248,12 +1289,15 @@ valid examples: // links start with '[' if (reader.get() != '[') { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage link caption doesn't start with '['"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): link caption doesn't start with '['", reader.str().c_str()); return false; } reader.getline(buffer, 256, ']'); + if (reader.eof()) + { + LOG("ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", reader.str().c_str()); + return false; + } // verify the link name if (linkedSpell) @@ -1265,19 +1309,21 @@ valid examples: SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(linkedSpell->Id); if (bounds.first == bounds.second) { + LOG("ChatHandler::isValidChatMessage('%s'): skill line not found for spell %u", reader.str().c_str(), linkedSpell->Id); return false; } SkillLineAbilityEntry const *skillInfo = bounds.first->second; - if (!skillInfo) { + LOG("ChatHandler::isValidChatMessage('%s'): skill line ability not found for spell %u", reader.str().c_str(), linkedSpell->Id); return false; } SkillLineEntry const *skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId); if (!skillLine) { + LOG("ChatHandler::isValidChatMessage('%s'): skill line not found for skill %u", reader.str().c_str(), skillInfo->skillId); return false; } @@ -1288,8 +1334,8 @@ valid examples: { // 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); + uint32 spellNameLength = strlen(buffer) - skillLineNameLength - 2; + memmove(buffer, buffer + skillLineNameLength + 2, spellNameLength + 1); } } } @@ -1310,12 +1356,9 @@ valid examples: if (linkedQuest->GetTitle() != buffer) { QuestLocale const *ql = sObjectMgr->GetQuestLocale(linkedQuest->GetQuestId()); - if (!ql) { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage default questname didn't match and there is no locale"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): default questname didn't match and no locales present for this quest (id: %u)", reader.str().c_str(), linkedQuest->GetQuestId()); return false; } @@ -1330,16 +1373,15 @@ valid examples: } if (!foundName) { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage no quest locale title matched"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): linked quest (id: %u) name wasn't found in any localization", reader.str().c_str(), linkedQuest->GetQuestId()); return false; } } } else if (linkedItem) { - char* const* suffix = itemSuffix?itemSuffix->nameSuffix:(itemProperty?itemProperty->nameSuffix:NULL); + char* const* suffix = itemSuffix ? itemSuffix->nameSuffix : + (itemProperty ? itemProperty->nameSuffix : NULL); std::string expectedName = std::string(linkedItem->Name1); if (suffix) @@ -1373,9 +1415,7 @@ valid examples: } if (!foundName) { -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage linked item name wasn't found in any localization"); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): linked item (id: %u) name wasn't found in any localization", reader.str().c_str(), linkedItem->ItemId); return false; } } @@ -1392,7 +1432,10 @@ valid examples: } } if (!foundName) + { + LOG("ChatHandler::isValidChatMessage('%s'): linked achievement (id: %u) name wasn't found in any localization", reader.str().c_str(), linkedAchievement->ID); return false; + } } // that place should never be reached - if nothing linked has been set in |H // it will return false before @@ -1405,19 +1448,19 @@ valid examples: // no further payload break; default: -#ifdef TRINITY_DEBUG - sLog->outBasic("ChatHandler::isValidChatMessage got invalid command |%c", commandChar); -#endif + LOG("ChatHandler::isValidChatMessage('%s'): got invalid command |%c", reader.str().c_str(), commandChar); return false; } } // check if every opened sequence was also closed properly -#ifdef TRINITY_DEBUG if (validSequence != validSequenceIterator) - sLog->outBasic("ChatHandler::isValidChatMessage EOF in active sequence"); -#endif - return validSequence == validSequenceIterator; + { + LOG("ChatHandler::isValidChatMessage('%s'): EOF in active sequence", reader.str().c_str()); + return false; + } + + return true; } bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd) diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index c79a8704946..a75d1af9cc1 100755 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -374,6 +374,7 @@ class ChatHandler void HandleCharacterDeletedListHelper(DeletedInfoList const& foundList); void HandleCharacterDeletedRestoreHelper(DeletedInfo const& delInfo); + uint32 _ReadUInt32(std::istringstream& reader) const; private: WorldSession * m_session; // != NULL for chat command call and NULL for CLI command |