[6982] Implemented gmlevel-based command security
[getmangos.git] / src / game / ChatHandler.cpp
bloba6e05aa64162a91478096bb68068c42f1bc20087
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Log.h"
21 #include "WorldPacket.h"
22 #include "WorldSession.h"
23 #include "World.h"
24 #include "Opcodes.h"
25 #include "ObjectMgr.h"
26 #include "Chat.h"
27 #include "Database/DatabaseEnv.h"
28 #include "ChannelMgr.h"
29 #include "Group.h"
30 #include "Guild.h"
31 #include "MapManager.h"
32 #include "ObjectAccessor.h"
33 #include "ScriptCalls.h"
34 #include "Player.h"
35 #include "SpellAuras.h"
36 #include "Language.h"
37 #include "Util.h"
39 void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
41 CHECK_PACKET_SIZE(recv_data,4+4+1);
43 uint32 type;
44 uint32 lang;
46 recv_data >> type;
47 recv_data >> lang;
49 if(type >= MAX_CHAT_MSG_TYPE)
51 sLog.outError("CHAT: Wrong message type received: %u", type);
52 return;
55 //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang );
57 // prevent talking at unknown language (cheating)
58 LanguageDesc const* langDesc = GetLanguageDescByID(lang);
59 if(!langDesc)
61 SendNotification(LANG_UNKNOWN_LANGUAGE);
62 return;
64 if(langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id))
66 // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
67 Unit::AuraList const& langAuras = _player->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE);
68 bool foundAura = false;
69 for(Unit::AuraList::const_iterator i = langAuras.begin();i != langAuras.end(); ++i)
71 if((*i)->GetModifier()->m_miscvalue == lang)
73 foundAura = true;
74 break;
77 if(!foundAura)
79 SendNotification(LANG_NOT_LEARNED_LANGUAGE);
80 return;
84 if(lang == LANG_ADDON)
86 // Disabled addon channel?
87 if(!sWorld.getConfig(CONFIG_ADDON_CHANNEL))
88 return;
90 // LANG_ADDON should not be changed nor be affected by flood control
91 else
93 // send in universal language if player in .gmon mode (ignore spell effects)
94 if (_player->isGameMaster())
95 lang = LANG_UNIVERSAL;
96 else
98 // send in universal language in two side iteration allowed mode
99 if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT))
100 lang = LANG_UNIVERSAL;
101 else
103 switch(type)
105 case CHAT_MSG_PARTY:
106 case CHAT_MSG_RAID:
107 case CHAT_MSG_RAID_LEADER:
108 case CHAT_MSG_RAID_WARNING:
109 // allow two side chat at group channel if two side group allowed
110 if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
111 lang = LANG_UNIVERSAL;
112 break;
113 case CHAT_MSG_GUILD:
114 case CHAT_MSG_OFFICER:
115 // allow two side chat at guild channel if two side guild allowed
116 if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
117 lang = LANG_UNIVERSAL;
118 break;
122 // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
123 Unit::AuraList const& ModLangAuras = _player->GetAurasByType(SPELL_AURA_MOD_LANGUAGE);
124 if(!ModLangAuras.empty())
125 lang = ModLangAuras.front()->GetModifier()->m_miscvalue;
128 if (!_player->CanSpeak())
130 std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
131 SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
132 return;
135 if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND)
136 GetPlayer()->UpdateSpeakTime();
139 switch(type)
141 case CHAT_MSG_SAY:
142 case CHAT_MSG_EMOTE:
143 case CHAT_MSG_YELL:
145 std::string msg = "";
146 recv_data >> msg;
148 if(msg.empty())
149 break;
151 if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
152 break;
154 // strip invisible characters for non-addon messages
155 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
156 stripLineInvisibleChars(msg);
158 if(msg.empty())
159 break;
161 if(type == CHAT_MSG_SAY)
162 GetPlayer()->Say(msg, lang);
163 else if(type == CHAT_MSG_EMOTE)
164 GetPlayer()->TextEmote(msg);
165 else if(type == CHAT_MSG_YELL)
166 GetPlayer()->Yell(msg, lang);
167 } break;
169 case CHAT_MSG_WHISPER:
171 std::string to, msg;
172 recv_data >> to;
173 CHECK_PACKET_SIZE(recv_data,4+4+(to.size()+1)+1);
174 recv_data >> msg;
176 // strip invisible characters for non-addon messages
177 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
178 stripLineInvisibleChars(msg);
180 if(msg.empty())
181 break;
183 if(!normalizePlayerName(to))
185 WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
186 data<<to;
187 SendPacket(&data);
188 break;
191 Player *player = objmgr.GetPlayer(to.c_str());
192 uint32 tSecurity = GetSecurity();
193 uint32 pSecurity = player ? player->GetSession()->GetSecurity() : 0;
194 if(!player || tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())
196 WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
197 data<<to;
198 SendPacket(&data);
199 return;
202 if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && tSecurity == SEC_PLAYER && pSecurity == SEC_PLAYER )
204 uint32 sidea = GetPlayer()->GetTeam();
205 uint32 sideb = player->GetTeam();
206 if( sidea != sideb )
208 WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
209 data<<to;
210 SendPacket(&data);
211 return;
215 GetPlayer()->Whisper(msg, lang,player->GetGUID());
216 } break;
218 case CHAT_MSG_PARTY:
220 std::string msg = "";
221 recv_data >> msg;
223 if(msg.empty())
224 break;
226 if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
227 break;
229 // strip invisible characters for non-addon messages
230 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
231 stripLineInvisibleChars(msg);
233 if(msg.empty())
234 break;
236 Group *group = GetPlayer()->GetGroup();
237 if(!group)
238 return;
240 WorldPacket data;
241 ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL);
242 group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID()));
244 break;
245 case CHAT_MSG_GUILD:
247 std::string msg = "";
248 recv_data >> msg;
250 if(msg.empty())
251 break;
253 if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
254 break;
256 // strip invisible characters for non-addon messages
257 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
258 stripLineInvisibleChars(msg);
260 if(msg.empty())
261 break;
263 if (GetPlayer()->GetGuildId())
265 Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
266 if (guild)
267 guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
270 break;
272 case CHAT_MSG_OFFICER:
274 std::string msg = "";
275 recv_data >> msg;
277 if(msg.empty())
278 break;
280 if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
281 break;
283 // strip invisible characters for non-addon messages
284 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
285 stripLineInvisibleChars(msg);
287 if(msg.empty())
288 break;
290 if (GetPlayer()->GetGuildId())
292 Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
293 if (guild)
294 guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
296 break;
298 case CHAT_MSG_RAID:
300 std::string msg="";
301 recv_data >> msg;
303 if(msg.empty())
304 break;
306 if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
307 break;
309 // strip invisible characters for non-addon messages
310 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
311 stripLineInvisibleChars(msg);
313 if(msg.empty())
314 break;
316 Group *group = GetPlayer()->GetGroup();
317 if(!group || !group->isRaidGroup())
318 return;
320 WorldPacket data;
321 ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
322 group->BroadcastPacket(&data);
323 } break;
324 case CHAT_MSG_RAID_LEADER:
326 std::string msg="";
327 recv_data >> msg;
329 if(msg.empty())
330 break;
332 if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
333 break;
335 // strip invisible characters for non-addon messages
336 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
337 stripLineInvisibleChars(msg);
339 if(msg.empty())
340 break;
342 Group *group = GetPlayer()->GetGroup();
343 if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
344 return;
346 WorldPacket data;
347 ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL);
348 group->BroadcastPacket(&data);
349 } break;
350 case CHAT_MSG_RAID_WARNING:
352 std::string msg="";
353 recv_data >> msg;
355 // strip invisible characters for non-addon messages
356 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
357 stripLineInvisibleChars(msg);
359 if(msg.empty())
360 break;
362 Group *group = GetPlayer()->GetGroup();
363 if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())))
364 return;
366 WorldPacket data;
367 ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL);
368 group->BroadcastPacket(&data);
369 } break;
371 case CHAT_MSG_BATTLEGROUND:
373 std::string msg="";
374 recv_data >> msg;
376 // strip invisible characters for non-addon messages
377 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
378 stripLineInvisibleChars(msg);
380 if(msg.empty())
381 break;
383 Group *group = GetPlayer()->GetGroup();
384 if(!group || !group->isRaidGroup())
385 return;
387 WorldPacket data;
388 ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL);
389 group->BroadcastPacket(&data);
390 } break;
392 case CHAT_MSG_BATTLEGROUND_LEADER:
394 std::string msg="";
395 recv_data >> msg;
397 // strip invisible characters for non-addon messages
398 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
399 stripLineInvisibleChars(msg);
401 if(msg.empty())
402 break;
404 Group *group = GetPlayer()->GetGroup();
405 if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
406 return;
408 WorldPacket data;
409 ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL);
410 group->BroadcastPacket(&data);
411 } break;
413 case CHAT_MSG_CHANNEL:
415 std::string channel = "", msg = "";
416 recv_data >> channel;
418 // recheck
419 CHECK_PACKET_SIZE(recv_data,4+4+(channel.size()+1)+1);
421 recv_data >> msg;
423 // strip invisible characters for non-addon messages
424 if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
425 stripLineInvisibleChars(msg);
427 if(msg.empty())
428 break;
430 if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
432 if(Channel *chn = cMgr->GetChannel(channel,_player))
433 chn->Say(_player->GetGUID(),msg.c_str(),lang);
435 } break;
437 case CHAT_MSG_AFK:
439 std::string msg;
440 recv_data >> msg;
442 if((msg.empty() || !_player->isAFK()) && !_player->isInCombat() )
444 if(!_player->isAFK())
446 if(msg.empty())
447 msg = GetMangosString(LANG_PLAYER_AFK_DEFAULT);
448 _player->afkMsg = msg;
450 _player->ToggleAFK();
451 if(_player->isAFK() && _player->isDND())
452 _player->ToggleDND();
454 } break;
456 case CHAT_MSG_DND:
458 std::string msg;
459 recv_data >> msg;
461 if(msg.empty() || !_player->isDND())
463 if(!_player->isDND())
465 if(msg.empty())
466 msg = GetMangosString(LANG_PLAYER_DND_DEFAULT);
467 _player->dndMsg = msg;
469 _player->ToggleDND();
470 if(_player->isDND() && _player->isAFK())
471 _player->ToggleAFK();
473 } break;
475 default:
476 sLog.outError("CHAT: unknown message type %u, lang: %u", type, lang);
477 break;
481 void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data )
483 if(!GetPlayer()->isAlive())
484 return;
485 CHECK_PACKET_SIZE(recv_data,4);
487 uint32 emote;
488 recv_data >> emote;
489 GetPlayer()->HandleEmoteCommand(emote);
492 void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
494 if(!GetPlayer()->isAlive())
495 return;
497 if (!GetPlayer()->CanSpeak())
499 std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
500 SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
501 return;
504 CHECK_PACKET_SIZE(recv_data,4+4+8);
506 uint32 text_emote, emoteNum;
507 uint64 guid;
509 recv_data >> text_emote;
510 recv_data >> emoteNum;
511 recv_data >> guid;
513 const char *nam = 0;
514 uint32 namlen = 1;
516 Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
517 Creature *pCreature = dynamic_cast<Creature *>(unit);
518 if(unit)
520 nam = unit->GetName();
521 namlen = (nam ? strlen(nam) : 0) + 1;
524 EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
525 if (em)
527 uint32 emote_anim = em->textid;
529 WorldPacket data;
531 switch(emote_anim)
533 case EMOTE_STATE_SLEEP:
534 case EMOTE_STATE_SIT:
535 case EMOTE_STATE_KNEEL:
536 case EMOTE_ONESHOT_NONE:
537 break;
538 default:
539 GetPlayer()->HandleEmoteCommand(emote_anim);
540 break;
543 data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
544 data << GetPlayer()->GetGUID();
545 data << (uint32)text_emote;
546 data << emoteNum;
547 data << (uint32)namlen;
548 if( namlen > 1 )
550 data.append(nam, namlen);
552 else
554 data << (uint8)0x00;
557 GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
559 //Send scripted event call
560 if (pCreature && Script)
561 Script->ReceiveEmote(GetPlayer(),pCreature,text_emote);
565 void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )
567 CHECK_PACKET_SIZE(recv_data, 8+1);
569 uint64 iguid;
570 uint8 unk;
571 //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED");
573 recv_data >> iguid;
574 recv_data >> unk; // probably related to spam reporting
576 Player *player = objmgr.GetPlayer(iguid);
577 if(!player || !player->GetSession())
578 return;
580 WorldPacket data;
581 ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(),NULL);
582 player->GetSession()->SendPacket(&data);