Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
ChatLink.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "AchievementMgr.h"
7#include "ChatLink.h"
8#include "DBCStores.h"
9#include "ObjectMgr.h"
10#include "SpellInfo.h"
11#include "SpellMgr.h"
12
13// Supported shift-links (client generated and server side)
14// |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r
15// - client, item icon shift click, not used in server currently
16// |color|Harea:area_id|h[name]|h|r
17// |color|Hcreature:creature_guid|h[name]|h|r
18// |color|Hcreature_entry:creature_id|h[name]|h|r
19// |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r - client, at shift click in recipes list dialog
20// |color|Hgameevent:id|h[name]|h|r
21// |color|Hgameobject:go_guid|h[name]|h|r
22// |color|Hgameobject_entry:go_id|h[name]|h|r
23// |color|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|h|r - client, at shift click in glyphs dialog, GlyphSlot.dbc, GlyphProperties.dbc
24// |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:0:0:0:reporter_level|h[name]|h|r
25// - client, item icon shift click
26// |color|Hitemset:itemset_id|h[name]|h|r
27// |color|Hplayer:name|h[name]|h|r - client, in some messages, at click copy only name instead link
28// |color|Hquest:quest_id:quest_level|h[name]|h|r - client, quest list name shift-click
29// |color|Hskill:skill_id|h[name]|h|r
30// |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click
31// |color|Htalent:talent_id, rank|h[name]|h|r - client, talent icon shift-click
32// |color|Htaxinode:id|h[name]|h|r
33// |color|Htele:id|h[name]|h|r
34// |color|Htitle:id|h[name]|h|r
35// |color|Htrade:spell_id:cur_value:max_value:unk3int:unk3str|h[name]|h|r - client, spellbook profession icon shift-click
36
37inline bool ReadUInt32(std::istringstream& iss, uint32& res)
38{
39 iss >> std::dec >> res;
40 return !iss.fail() && !iss.eof();
41}
42
43inline bool ReadInt32(std::istringstream& iss, int32& res)
44{
45 iss >> std::dec >> res;
46 return !iss.fail() && !iss.eof();
47}
48
49inline std::string ReadSkip(std::istringstream& iss, char term)
50{
51 std::string res;
52 char c = iss.peek();
53 while (c != term && c != '\0')
54 {
55 res += c;
56 iss.ignore(1);
57 c = iss.peek();
58 }
59 return res;
60}
61
62inline bool CheckDelimiter(std::istringstream& iss, char delimiter, const char* context)
63{
64 char c = iss.peek();
65 if (c != delimiter)
66 {
67 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid %s link structure ('%c' expected, '%c' found)", iss.str().c_str(), context, delimiter, c);
68 return false;
69 }
70 iss.ignore(1);
71 return true;
72}
73
74inline bool ReadHex(std::istringstream& iss, uint32& res, uint32 length)
75{
76 std::istringstream::pos_type pos = iss.tellg();
77 iss >> std::hex >> res;
78 //uint32 size = uint32(iss.gcount());
79 if (length && uint32(iss.tellg() - pos) != length)
80 return false;
81 return !iss.fail() && !iss.eof();
82}
83
84#define DELIMITER ':'
85#define PIPE_CHAR '|'
86
87bool ChatLink::ValidateName(char* buffer, const char* /*context*/)
88{
89 _name = buffer;
90 return true;
91}
92
93// |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:random_property:0:reporter_level|h[name]|h|r
94// |cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r
95bool ItemChatLink::Initialize(std::istringstream& iss)
96{
97 // Read item entry
98 uint32 itemEntry = 0;
99 if (!ReadUInt32(iss, itemEntry))
100 {
101 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item entry", iss.str().c_str());
102 return false;
103 }
104 // Validate item
105 _item = sObjectMgr->GetItemTemplate(itemEntry);
106 if (!_item)
107 {
108 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid itemEntry %u in |item command", iss.str().c_str(), itemEntry);
109 return false;
110 }
111 // Validate item's color
112 if (_color != ItemQualityColors[_item->Quality])
113 {
114 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item has color %u, but user claims %u", iss.str().c_str(), ItemQualityColors[_item->Quality], _color);
115 return false;
116 }
117 // Number of various item properties after item entry
118 const uint8 propsCount = 8;
119 const uint8 randomPropertyPosition = 5;
120 for (uint8 index = 0; index < propsCount; ++index)
121 {
122 if (!CheckDelimiter(iss, DELIMITER, "item"))
123 return false;
124
125 int32 id = 0;
126 if (!ReadInt32(iss, id))
127 {
128 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading item property (%u)", iss.str().c_str(), index);
129 return false;
130 }
131 if (id && (index == randomPropertyPosition))
132 {
133 // Validate random property
134 if (id > 0)
135 {
136 _property = sItemRandomPropertiesStore.LookupEntry(id);
137 if (!_property)
138 {
139 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid item property id %u in |item command", iss.str().c_str(), id);
140 return false;
141 }
142 }
143 else if (id < 0)
144 {
145 _suffix = sItemRandomSuffixStore.LookupEntry(-id);
146 if (!_suffix)
147 {
148 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid item suffix id %u in |item command", iss.str().c_str(), -id);
149 return false;
150 }
151 }
152 }
153 _data[index] = id;
154 }
155 return true;
156}
157
158inline std::string ItemChatLink::FormatName(uint8 index, ItemLocale const* locale, char* suffixStrings) const
159{
160 std::stringstream ss;
161 if (locale == NULL || index >= locale->Name.size())
162 ss << _item->Name1;
163 else
164 ss << locale->Name[index];
165 if (suffixStrings)
166 ss << ' ' << suffixStrings[index];
167 return ss.str();
168}
169
170bool ItemChatLink::ValidateName(char* buffer, const char* context)
171{
172 ChatLink::ValidateName(buffer, context);
173
174 char* suffixStrings = _suffix ? _suffix->nameSuffix : (_property ? _property->nameSuffix : NULL);
175
176 bool res = (FormatName(LOCALE_enUS, NULL, suffixStrings) == buffer);
177 if (!res)
178 {
179 ItemLocale const* il = sObjectMgr->GetItemLocale(_item->ItemId);
180 for (uint8 index = LOCALE_koKR; index < TOTAL_LOCALES; ++index)
181 {
182 if (FormatName(index, il, suffixStrings) == buffer)
183 {
184 res = true;
185 break;
186 }
187 }
188 }
189 if (!res)
190 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked item (id: %u) name wasn't found in any localization", context, _item->ItemId);
191 return res;
192}
193
194// |color|Hquest:quest_id:quest_level|h[name]|h|r
195// |cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r
196bool QuestChatLink::Initialize(std::istringstream& iss)
197{
198 // Read quest id
199 uint32 questId = 0;
200 if (!ReadUInt32(iss, questId))
201 {
202 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest entry", iss.str().c_str());
203 return false;
204 }
205 // Validate quest
206 _quest = sObjectMgr->GetQuestTemplate(questId);
207 if (!_quest)
208 {
209 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): quest template %u not found", iss.str().c_str(), questId);
210 return false;
211 }
212 // Check delimiter
213 if (!CheckDelimiter(iss, DELIMITER, "quest"))
214 return false;
215 // Read quest level
216 if (!ReadInt32(iss, _questLevel))
217 {
218 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading quest level", iss.str().c_str());
219 return false;
220 }
221 // Validate quest level
223 {
224 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): quest level %d is too big", iss.str().c_str(), _questLevel);
225 return false;
226 }
227 return true;
228}
229
230bool QuestChatLink::ValidateName(char* buffer, const char* context)
231{
232 ChatLink::ValidateName(buffer, context);
233
234 bool res = (_quest->GetTitle() == buffer);
235 if (!res)
236 if (QuestLocale const* ql = sObjectMgr->GetQuestLocale(_quest->GetQuestId()))
237 for (uint8 i = 0; i < ql->Title.size(); i++)
238 if (ql->Title[i] == buffer)
239 {
240 res = true;
241 break;
242 }
243 if (!res)
244 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked quest (id: %u) title wasn't found in any localization", context, _quest->GetQuestId());
245 return res;
246}
247
248// |color|Hspell:spell_id|h[name]|h|r
249// |cff71d5ff|Hspell:21563|h[Command]|h|r
250bool SpellChatLink::Initialize(std::istringstream& iss)
251{
253 return false;
254 // Read spell id
255 uint32 spellId = 0;
256 if (!ReadUInt32(iss, spellId))
257 {
258 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading spell entry", iss.str().c_str());
259 return false;
260 }
261 // Validate spell
262 _spell = sSpellMgr->GetSpellInfo(spellId);
263 if (!_spell)
264 {
265 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |spell command", iss.str().c_str(), spellId);
266 return false;
267 }
268 return true;
269}
270
271bool SpellChatLink::ValidateName(char* buffer, const char* context)
272{
273 ChatLink::ValidateName(buffer, context);
274
275 // spells with that flag have a prefix of "$PROFESSION: "
276 if (_spell->Attributes & SPELL_ATTR0_TRADESPELL)
277 {
278 SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(_spell->Id);
279 if (bounds.first == bounds.second)
280 {
281 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line not found for spell %u", context, _spell->Id);
282 return false;
283 }
284 SkillLineAbilityEntry const* skillInfo = bounds.first->second;
285 if (!skillInfo)
286 {
287 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line ability not found for spell %u", context, _spell->Id);
288 return false;
289 }
290 SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId);
291 if (!skillLine)
292 {
293 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): skill line not found for skill %u", context, skillInfo->skillId);
294 return false;
295 }
296
297 uint32 skillLineNameLength = strlen(skillLine->name);
298 if (skillLineNameLength > 0 && strncmp(skillLine->name, buffer, skillLineNameLength) == 0)
299 {
300 // found the prefix, remove it to perform spellname validation below
301 // -2 = strlen(": ")
302 uint32 spellNameLength = strlen(buffer) - skillLineNameLength - 2;
303 memcpy(buffer, buffer + skillLineNameLength + 2, spellNameLength + 1);
304 }
305 }
306
307 if (*_spell->SpellName && strcmp(_spell->SpellName, buffer) == 0)
308 return true;
309
310 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked spell (id: %u) name wasn't found in any localization", context, _spell->Id);
311 return false;
312}
313
314// |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r
315// |cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r
316bool AchievementChatLink::Initialize(std::istringstream& iss)
317{
319 return false;
320 // Read achievemnt Id
321 uint32 achievementId = 0;
322 if (!ReadUInt32(iss, achievementId))
323 {
324 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement entry", iss.str().c_str());
325 return false;
326 }
327 // Validate achievement
328 _achievement = sAchievementMgr->GetAchievement(achievementId);
329 if (!_achievement)
330 {
331 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid achivement id %u in |achievement command", iss.str().c_str(), achievementId);
332 return false;
333 }
334 // Check delimiter
335 if (!CheckDelimiter(iss, DELIMITER, "achievement"))
336 return false;
337 // Read HEX
338 if (!ReadHex(iss, _guid, 0))
339 {
340 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid hexadecimal number while reading char's guid", iss.str().c_str());
341 return false;
342 }
343 // Skip progress
344 const uint8 propsCount = 8;
345 for (uint8 index = 0; index < propsCount; ++index)
346 {
347 if (!CheckDelimiter(iss, DELIMITER, "achievement"))
348 return false;
349
350 if (!ReadUInt32(iss, _data[index]))
351 {
352 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement property (%u)", iss.str().c_str(), index);
353 return false;
354 }
355 }
356 return true;
357}
358
359bool AchievementChatLink::ValidateName(char* buffer, const char* context)
360{
361 ChatLink::ValidateName(buffer, context);
362
363 if (*_achievement->name && strcmp(_achievement->name, buffer) == 0)
364 return true;
365
366 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked achievement (id: %u) name wasn't found in any localization", context, _achievement->ID);
367 return false;
368}
369
370// |color|Htrade:spell_id:cur_value:max_value:player_guid:base64_data|h[name]|h|r
371// |cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r
372bool TradeChatLink::Initialize(std::istringstream& iss)
373{
375 return false;
376 // Spell Id
377 uint32 spellId = 0;
378 if (!ReadUInt32(iss, spellId))
379 {
380 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement entry", iss.str().c_str());
381 return false;
382 }
383 // Validate spell
384 _spell = sSpellMgr->GetSpellInfo(spellId);
385 if (!_spell)
386 {
387 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), spellId);
388 return false;
389 }
390 // Check delimiter
391 if (!CheckDelimiter(iss, DELIMITER, "trade"))
392 return false;
393 // Minimum talent level
394 if (!ReadInt32(iss, _minSkillLevel))
395 {
396 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading minimum talent level", iss.str().c_str());
397 return false;
398 }
399 // Check delimiter
400 if (!CheckDelimiter(iss, DELIMITER, "trade"))
401 return false;
402 // Maximum talent level
403 if (!ReadInt32(iss, _maxSkillLevel))
404 {
405 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading maximum talent level", iss.str().c_str());
406 return false;
407 }
408 // Check delimiter
409 if (!CheckDelimiter(iss, DELIMITER, "trade"))
410 return false;
411 // Something hexadecimal
412 if (!ReadHex(iss, _guid, 0))
413 {
414 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading achievement's owner guid", iss.str().c_str());
415 return false;
416 }
417 // Skip base64 encoded stuff
418 _base64 = ReadSkip(iss, PIPE_CHAR);
419 return true;
420}
421
422// |color|Htalent:talent_id:rank|h[name]|h|r
423// |cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r
424bool TalentChatLink::Initialize(std::istringstream& iss)
425{
427 return false;
428 // Read talent entry
429 if (!ReadUInt32(iss, _talentId))
430 {
431 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading talent entry", iss.str().c_str());
432 return false;
433 }
434 // Validate talent
435 TalentEntry const* talentInfo = sTalentStore.LookupEntry(_talentId);
436 if (!talentInfo)
437 {
438 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid talent id %u in |talent command", iss.str().c_str(), _talentId);
439 return false;
440 }
441 // Validate talent's spell
442 _spell = sSpellMgr->GetSpellInfo(talentInfo->SpellId);
443 if (!_spell)
444 {
445 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), talentInfo->SpellId);
446 return false;
447 }
448 // Delimiter
449 if (!CheckDelimiter(iss, DELIMITER, "talent"))
450 return false;
451 // Rank
452 if (!ReadInt32(iss, _rankId))
453 {
454 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading talent rank", iss.str().c_str());
455 return false;
456 }
457 return true;
458}
459
460// |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r
461// |cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r
462bool EnchantmentChatLink::Initialize(std::istringstream& iss)
463{
465 return false;
466 // Spell Id
467 uint32 spellId = 0;
468 if (!ReadUInt32(iss, spellId))
469 {
470 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading enchantment spell entry", iss.str().c_str());
471 return false;
472 }
473 // Validate spell
474 _spell = sSpellMgr->GetSpellInfo(spellId);
475 if (!_spell)
476 {
477 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |enchant command", iss.str().c_str(), spellId);
478 return false;
479 }
480 return true;
481}
482
483// |color|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|h|r
484// |cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|h|r
485bool GlyphChatLink::Initialize(std::istringstream& iss)
486{
488 return false;
489 // Slot
490 if (!ReadUInt32(iss, _slotId))
491 {
492 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading slot id", iss.str().c_str());
493 return false;
494 }
495 // Check delimiter
496 if (!CheckDelimiter(iss, DELIMITER, "glyph"))
497 return false;
498 // Glyph Id
499 uint32 glyphId = 0;
500 if (!ReadUInt32(iss, glyphId))
501 {
502 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly while reading glyph entry", iss.str().c_str());
503 return false;
504 }
505 // Validate glyph
506 _glyph = sGlyphPropertiesStore.LookupEntry(glyphId);
507 if (!_glyph)
508 {
509 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid glyph id %u in |glyph command", iss.str().c_str(), glyphId);
510 return false;
511 }
512 // Validate glyph's spell
513 _spell = sSpellMgr->GetSpellInfo(_glyph->SpellId);
514 if (!_spell)
515 {
516 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |glyph command", iss.str().c_str(), _glyph->SpellId);
517 return false;
518 }
519 return true;
520}
521
522LinkExtractor::LinkExtractor(const char* msg) : _iss(msg) { }
523
525{
526 for (Links::iterator itr = _links.begin(); itr != _links.end(); ++itr)
527 delete* itr;
528 _links.clear();
529}
530
532{
533 const char validSequence[6] = "cHhhr";
534 const char* validSequenceIterator = validSequence;
535
536 char buffer[256];
537
538 std::istringstream::pos_type startPos = 0;
539 uint32 color = 0;
540
541 ChatLink* link = NULL;
542 while (!_iss.eof())
543 {
544 if (validSequence == validSequenceIterator)
545 {
546 link = NULL;
547 _iss.ignore(255, PIPE_CHAR);
548 startPos = _iss.tellg() - std::istringstream::pos_type(1);
549 }
550 else if (_iss.get() != PIPE_CHAR)
551 {
552 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence aborted unexpectedly", _iss.str().c_str());
553 return false;
554 }
555
556 // pipe has always to be followed by at least one char
557 if (_iss.peek() == '\0')
558 {
559 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): pipe followed by '\\0'", _iss.str().c_str());
560 return false;
561 }
562
563 // no further pipe commands
564 if (_iss.eof())
565 break;
566
567 char commandChar;
568 _iss >> commandChar;
569
570 // | in normal messages is escaped by ||
571 if (commandChar != PIPE_CHAR)
572 {
573 if (commandChar == *validSequenceIterator)
574 {
575 if (validSequenceIterator == validSequence + 4)
576 validSequenceIterator = validSequence;
577 else
578 ++validSequenceIterator;
579 }
580 else
581 {
582 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid sequence, expected '%c' but got '%c'", _iss.str().c_str(), *validSequenceIterator, commandChar);
583 return false;
584 }
585 }
586 else if (validSequence != validSequenceIterator)
587 {
588 // no escaped pipes in sequences
589 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got escaped pipe in sequence", _iss.str().c_str());
590 return false;
591 }
592
593 switch (commandChar)
594 {
595 case 'c':
596 if (!ReadHex(_iss, color, 8))
597 {
598 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): invalid hexadecimal number while reading color", _iss.str().c_str());
599 return false;
600 }
601 break;
602 case 'H':
603 // read chars up to colon = link type
604 _iss.getline(buffer, 256, DELIMITER);
605 if (_iss.eof())
606 {
607 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", _iss.str().c_str());
608 return false;
609 }
610
611 if (strcmp(buffer, "item") == 0)
612 link = new ItemChatLink();
613 else if (strcmp(buffer, "quest") == 0)
614 link = new QuestChatLink();
615 else if (strcmp(buffer, "trade") == 0)
616 link = new TradeChatLink();
617 else if (strcmp(buffer, "talent") == 0)
618 link = new TalentChatLink();
619 else if (strcmp(buffer, "spell") == 0)
620 link = new SpellChatLink();
621 else if (strcmp(buffer, "enchant") == 0)
622 link = new EnchantmentChatLink();
623 else if (strcmp(buffer, "achievement") == 0)
624 link = new AchievementChatLink();
625 else if (strcmp(buffer, "glyph") == 0)
626 link = new GlyphChatLink();
627 else
628 {
629 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): user sent unsupported link type '%s'", _iss.str().c_str(), buffer);
630 return false;
631 }
632 _links.push_back(link);
633 link->SetColor(color);
634 if (!link->Initialize(_iss))
635 return false;
636 break;
637 case 'h':
638 // if h is next element in sequence, this one must contain the linked text :)
639 if (*validSequenceIterator == 'h')
640 {
641 // links start with '['
642 if (_iss.get() != '[')
643 {
644 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): link caption doesn't start with '['", _iss.str().c_str());
645 return false;
646 }
647 _iss.getline(buffer, 256, ']');
648 if (_iss.eof())
649 {
650 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): sequence finished unexpectedly", _iss.str().c_str());
651 return false;
652 }
653
654 if (!link)
655 return false;
656
657 if (!link->ValidateName(buffer, _iss.str().c_str()))
658 return false;
659 }
660 break;
661 case 'r':
662 if (link)
663 link->SetBounds(startPos, _iss.tellg());
664 case '|':
665 // no further payload
666 break;
667 default:
668 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid command |%c", _iss.str().c_str(), commandChar);
669 return false;
670 }
671 }
672
673 // check if every opened sequence was also closed properly
674 if (validSequence != validSequenceIterator)
675 {
676 SF_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): EOF in active sequence", _iss.str().c_str());
677 return false;
678 }
679
680 return true;
681}
#define sAchievementMgr
const uint8 TOTAL_LOCALES
Definition Common.h:153
@ LOCALE_enUS
Definition Common.h:139
@ LOCALE_koKR
Definition Common.h:140
@ STRONG_MAX_LEVEL
Definition DBCEnums.h:24
DBCStorage< ItemRandomSuffixEntry > sItemRandomSuffixStore(ItemRandomSuffixfmt)
DBCStorage< ItemRandomPropertiesEntry > sItemRandomPropertiesStore(ItemRandomPropertiesfmt)
DBCStorage< SkillLineEntry > sSkillLineStore(SkillLinefmt)
DBCStorage< TalentEntry > sTalentStore(TalentEntryfmt)
DBCStorage< GlyphPropertiesEntry > sGlyphPropertiesStore(GlyphPropertiesfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
#define SF_LOG_TRACE(filterType__,...)
Definition Log.h:131
#define sObjectMgr
Definition ObjectMgr.h:1617
@ SPELL_ATTR0_TRADESPELL
const uint32 ItemQualityColors[MAX_ITEM_QUALITY]
@ CHAT_LINK_COLOR_TRADE
@ CHAT_LINK_COLOR_SPELL
@ CHAT_LINK_COLOR_ACHIEVEMENT
@ CHAT_LINK_COLOR_TALENT
@ CHAT_LINK_COLOR_GLYPH
@ CHAT_LINK_COLOR_ENCHANT
#define sSpellMgr
Definition SpellMgr.h:744
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition SpellMgr.h:544
StringVector Name
uint32 skillId
char * name
uint32 SpellId