All pastes #1693654 Raw Edit

Anonymous

public diff v1 · immutable
#1693654 ·published 2009-11-30 08:32 UTC
rendered paste body
diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cppindex d043af4..22521e9 100644--- a/src/game/ChatHandler.cpp+++ b/src/game/ChatHandler.cpp@@ -18,6 +18,7 @@  #include "Common.h" #include "Log.h"+#include "ChatLog.h" #include "WorldPacket.h" #include "WorldSession.h" #include "World.h"@@ -179,11 +180,23 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )                 break;              if(type == CHAT_MSG_SAY)+            {+                sChatLog.ChatMsg(GetPlayer(), msg, type);+                 GetPlayer()->Say(msg, lang);+            }             else if(type == CHAT_MSG_EMOTE)+            {+                sChatLog.ChatMsg(GetPlayer(), msg, type);+                 GetPlayer()->TextEmote(msg);+            }             else if(type == CHAT_MSG_YELL)+            {+                sChatLog.ChatMsg(GetPlayer(), msg, type);+                 GetPlayer()->Yell(msg, lang);+            }         } break;          case CHAT_MSG_WHISPER:@@ -209,6 +222,9 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             Player *player = sObjectMgr.GetPlayer(to.c_str());             uint32 tSecurity = GetSecurity();             uint32 pSecurity = player ? player->GetSession()->GetSecurity() : SEC_PLAYER;++            sChatLog.WhisperMsg(GetPlayer(), to, msg);+             if (!player || (tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers()))             {                 WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));@@ -250,6 +266,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.PartyMsg(GetPlayer(), msg);+             // if player is in battleground, he cannot say to battleground members by /p             Group *group = GetPlayer()->GetOriginalGroup();             // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid, then return@@ -278,6 +296,10 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.GuildMsg(GetPlayer(), msg, false);++            sChatLog.GuildMsg(GetPlayer(), msg, true);+             if (GetPlayer()->GetGuildId())             {                 Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId());@@ -329,6 +351,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.RaidMsg(GetPlayer(), msg, type);+             // if player is in battleground, he cannot say to battleground members by /ra             Group *group = GetPlayer()->GetOriginalGroup();             // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid or his group isn't raid, then return@@ -356,6 +380,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.RaidMsg(GetPlayer(), msg, type);+             // if player is in battleground, he cannot say to battleground members by /ra             Group *group = GetPlayer()->GetOriginalGroup();             if ((!group && !(group = GetPlayer()->GetGroup())) || group->isBGGroup() || !group->isRaidGroup())@@ -376,6 +402,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.RaidMsg(GetPlayer(), msg, type);+             Group *group = GetPlayer()->GetGroup();             if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())))                 return;@@ -397,6 +425,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.BattleGroundMsg(GetPlayer(), msg, type);+             //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()             Group *group = GetPlayer()->GetGroup();             if(!group || !group->isBGGroup())@@ -418,6 +448,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.BattleGroundMsg(GetPlayer(), msg, type);+             //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()             Group *group = GetPlayer()->GetGroup();             if(!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID()))@@ -441,6 +473,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )             if(msg.empty())                 break; +            sChatLog.ChannelMsg(GetPlayer(), channel, msg);+             if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))             {                 if(Channel *chn = cMgr->GetChannel(channel,_player))diff --git a/src/game/Makefile.am b/src/game/Makefile.amindex d13bc32..45cbae1 100644--- a/src/game/Makefile.am+++ b/src/game/Makefile.am@@ -88,6 +88,10 @@ libmangosgame_a_SOURCES = \ 	Chat.cpp \ 	Chat.h \ 	ChatHandler.cpp \+    ChatLexicsCutter.cpp \+    ChatLexicsCutter.h \+    ChatLog.cpp \+    ChatLog.h \ 	CombatHandler.cpp \ 	ConfusedMovementGenerator.cpp \ 	ConfusedMovementGenerator.h \diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.inindex 479a6ce..efdf400 100644--- a/src/mangosd/mangosd.conf.dist.in+++ b/src/mangosd/mangosd.conf.dist.in@@ -1374,3 +1374,74 @@ Ra.IP = 0.0.0.0 Anticheat.Movement.MaxXYT = 0.04 Anticheat.Movement.IgnoreSecAfterTeleport = 10 Anticheat.Movement.GmLevel = 0++# Chat log parameters+ChatLogEnable = 0++# If this is enabled, all $d in file names are replaced with current date+# This does include innormative lexics log+ChatLogDateSplit = 1++# If this is enabled, UTF8 header is written into new files+ChatLogUTFHeader = 1++# If this is enabled, chat log will ignore messages with unprintable chars+ChatLogIgnoreUnprintable = 1++# Chat log files+ChatLogChatFile = main_chat-$d.log+ChatLogPartyFile = party_chat-$d.log+ChatLogGuildFile = guild_chat-$d.log+ChatLogWhisperFile = whisper_chat-$d.log+ChatLogChannelFile = channel_chat-$d.log+ChatLogRaidFile = raid_chat-$d.log+ChatLogBattleGroundFile = bg_chat-$d.log++# Chat log screen logging+ChatLogChatScreen = 0+ChatLogPartyScreen = 0+ChatLogGuildScreen = 0+ChatLogWhisperScreen = 0+ChatLogChannelScreen = 0+ChatLogRaidScreen = 0+ChatLogBattleGroundScreen = 0++# Lexics cutter parameters+LexicsCutterEnable = 1++LexicsCutterInnormativeCut = 1+LexicsCutterCutReplacement = &!@^%!^&*!!!+LexicsCutterLogFile = innormative-$d.log+LexicsCutterScreenLog = 0+LexicsCutterAnalogsFile = letter_analogs.txt+LexicsCutterWordsFile = innormative_words.txt++# Where to cut lexics+LexicsCutInChat = 1+LexicsCutInParty = 1+LexicsCutInGuild = 1+LexicsCutInWhisper = 1+LexicsCutInChannel = 1+LexicsCutInRaid = 1+LexicsCutInBattleGround = 1++# Ignore word spaces like: W O R D+LexicsCutterIgnoreSpaces = 1++# Ignore repeats like: WWOOOORRRRRD+LexicsCutterIgnoreRepeats = 1++# --- Action:+# ---   0: log only+# ---   1: sheep+# ---   2: stun+# ---   3: kill+# ---   4: leave 5 health+# ---   5: disable chat+# ---   6: stuck (works as stun + 50% health) [by KAPATEJIb]+# ---   7: resurrection sickness [by Koshei]+LexicsCutterAction = 0+LexicsCutterActionDuration = 60000++# Do not perform action on GM if this is enabled+LexicsCutterNoActionOnGM = 1diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcprojindex 590a5dc..81c5aca 100644--- a/win/VC80/game.vcproj+++ b/win/VC80/game.vcproj@@ -713,6 +713,22 @@ 				RelativePath="..\..\src\game\ChatHandler.cpp" 				> 			</File>+            <File+                RelativePath="..\..\src\game\ChatLexicsCutter.cpp"+                >+            </File>+            <File+                RelativePath="..\..\src\game\ChatLexicsCutter.h"+                >+            </File>+            <File+                RelativePath="..\..\src\game\ChatLog.cpp"+                >+            </File>+            <File+                RelativePath="..\..\src\game\ChatLog.h"+                >+            </File> 			<File 				RelativePath="..\..\src\game\CombatHandler.cpp" 				>diff --git a/win/VC90/game.vcproj b/win/VC90/game.vcprojindex d860b9f..3d6cbca 100644--- a/win/VC90/game.vcproj+++ b/win/VC90/game.vcproj@@ -715,6 +715,22 @@ 				> 			</File> 			<File+				RelativePath="..\..\src\game\ChatLexicsCutter.cpp"+				>+			</File>+			<File+				RelativePath="..\..\src\game\ChatLexicsCutter.h"+				>+			</File>+			<File+				RelativePath="..\..\src\game\ChatLog.cpp"+				>+			</File>+			<File+				RelativePath="..\..\src\game\ChatLog.h"+				>+			</File>+			<File 				RelativePath="..\..\src\game\CombatHandler.cpp" 				> 			</File>diff --git a/src/game/ChatLexicsCutter.cpp b/src/game/ChatLexicsCutter.cppnew file mode 100644index 0000000..1c1d555--- /dev/null+++ b/src/game/ChatLexicsCutter.cpp@@ -0,0 +1,274 @@+/* + * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>+ *+ * 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, write to the Free Software+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA+ */++#include "Common.h"+#include "ChatLexicsCutter.h"++LexicsCutter::LexicsCutter()+{+    InvalidChars = "~`!@#$%^&*()-_+=[{]}|\\;:'\",<.>/?";+}++bool LexicsCutter::ReadUTF8(std::string& in, std::string& out, unsigned int& pos)+{+    if (pos >= in.length()) return false;+    +    out = "";+    unsigned char c = in[pos++];+    out += c;+    int toread = trailingBytesForUTF8[(int) c];+    while ((pos < in.length()) && (toread > 0))+    {+        out += in[pos++];+        toread--;+    }+    +    return true;+}++std::string LexicsCutter::trim(std::string& s, const std::string& drop)+{+    std::string r = s.erase(s.find_last_not_of(drop) + 1);+    return r.erase(0, r.find_first_not_of(drop));+}++bool LexicsCutter::Read_Letter_Analogs(std::string& FileName)+{+    FILE *ma_file;+    char line[1024];+    unsigned int pos;+    std::string line_s;+    std::string lchar;+    std::string lanalog;+    +    ma_file = fopen(FileName.c_str(), "rb");+    +    while (!feof(ma_file))+    {+        line[0] = 0x0;+        fgets(line, 1020, ma_file);++        // check for UTF8 prefix and comments+        if (strlen(line) >= 3)+        {+            if (line[0] == '\xEF' && line[1] == '\xBB' && line[2] == '\xBF')+            {+                strncpy(&line[0], &line[3], strlen(line) - 3);+            }+        }++        if (strlen(line) >= 2)+        {+            if (line[0] == '/' && line[1] == '/') continue;+        }++        // check for empty string+        line_s = line; +        line_s = trim(line_s, "\x0A\x0D\x20");+        if (line_s == "") continue;++        // process line without CR/LF+        line_s = line; +        line_s = trim(line_s, "\x0A\x0D");+    +        pos = 0;+        if (ReadUTF8(line_s, lchar, pos))+        {+            // create analogs vector+            LC_AnalogVector av;+            while (ReadUTF8(line_s, lanalog, pos))+            {+                av.push_back(lanalog);+            }+        +            // store vector in hash map+            AnalogMap[lchar] = av;+        }+    }+    +    fclose(ma_file);+    +    return true;+}++bool LexicsCutter::Read_Innormative_Words(std::string& FileName)+{+    FILE *ma_file;+    char line[1024];+    unsigned int pos;+    std::string line_s;+    std::string lchar;+    +    ma_file = fopen(FileName.c_str(), "rb");+    +    while (!feof(ma_file))+    {+        line[0] = 0x0;+        fgets(line, 1020, ma_file);++        // check for UTF8 prefix and comment+        if (strlen(line) >= 3)+        {+            if (line[0] == '\xEF' && line[1] == '\xBB' && line[2] == '\xBF')+            {+                strncpy(&line[0], &line[3], strlen(line) - 3);+            }+        }++        if (strlen(line) >= 2)+        {+            if (line[0] == '/' && line[1] == '/') continue;+        }++        // check for empty string+        line_s = line; +        line_s = trim(line_s, "\x0A\x0D\x20");+        if (line_s == "") continue;++        // process line without CR/LF+        line_s = line; +        line_s = trim(line_s, "\x0A\x0D");+    +        // create word vector of vectors+        LC_WordVector vw;+        pos = 0;+        while (ReadUTF8(line_s, lchar, pos))+        {+            // create letter set+            LC_LetterSet vl;+        +            // initialize letter set with letter read+            vl.insert(lchar);+        +            // find letter analogs and push them onto the vector+            LC_AnalogMap::iterator itr = AnalogMap.find(lchar);+            if (itr != AnalogMap.end())+            {+                // analogs present, iterate+                for (LC_AnalogVector::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++)+                {+                    vl.insert(*itr2);+                }+            }+        +            // add letter vector to word vector+            vw.push_back(vl);+        }++        // push new word to words list+        WordList.push_back(vw);+    }+    +    fclose(ma_file);+    +    return true;+}++void LexicsCutter::Map_Innormative_Words()+{+    // process all the words in the vector+    for (unsigned int i = 0; i < WordList.size(); i++)+    {+        // parse all analogs in the first word letter+        for (LC_LetterSet::iterator itr = (*WordList[i].begin()).begin(); itr != (*WordList[i].begin()).end(); itr++)+        {+            // map the word to its first letter variants+            WordMap.insert(std::pair< std::string, unsigned int >(*itr, i));+        }+    }+}++bool LexicsCutter::Compare_Word(std::string& str, unsigned int pos, LC_WordVector word)+{+   std::string lchar_prev;+    std::string lchar;++   // read first letter of the word into lchar_prev+   ReadUTF8(str, lchar, pos);    ++    // okay, here we go, comparing word+    // first letter is already okay, we do begin from second and go on+    LC_WordVector::iterator i = word.begin();+    i++;+    while (i != word.end())+    {+        // get letter from word, return false if the string is shorter+        if (!ReadUTF8(str, lchar, pos)) return(false);+        // check, if the letter is in the set+        LC_LetterSet ls = *i;+        if (ls.count(lchar) == 0)+       {+           // letter is not in set, but we must check, if it is not space or repeat+           if ( (!(IgnoreMiddleSpaces && (lchar == " "))) &&+               (!(IgnoreLetterRepeat && (lchar == lchar_prev))) )+           {+               // no checks viable+               return(false);+           }+       }+       else+       {+           // next word letter+           i++;+       }+       // set previous string letter to compare if needed (this check can really conserve time)+       if (IgnoreLetterRepeat) lchar_prev = lchar;+   }+    +    return(true);+}++bool LexicsCutter::Check_Lexics(std::string& Phrase)+{+    std::string lchar;+    LC_WordMap::iterator i;+    std::pair< LC_WordMap::iterator, LC_WordMap::iterator > ii;++    if (Phrase.size() == 0) return(false);+    +    // first, convert the string, adding spaces and removing invalid characters+    // also create fast position vector for the new positions+    std::string str = " ";+    unsigned int pos = 0;+    while (ReadUTF8(Phrase, lchar, pos))+    {+        if (InvalidChars.find(lchar) == std::string::npos)+        {+            str.append(lchar);+        }+    }+    +    // string prepared, now parse it and scan for all the words+   unsigned int pos_prev = 0;+    pos = 0;+    while (ReadUTF8(str, lchar, pos))+    {+        // got character, now try to find wordmap for it+        ii = WordMap.equal_range(lchar);+        // iterate over all found words+        for (i = ii.first; i != ii.second; i++)+        {+            // compare word at initial position+            if (Compare_Word(str, pos_prev, WordList[i->second])) return(true);+        }+       // set initial position to the current position+       pos_prev = pos;+    }+    +    return(false);+}diff --git a/src/game/ChatLexicsCutter.h b/src/game/ChatLexicsCutter.hnew file mode 100644index 0000000..38d636c--- /dev/null+++ b/src/game/ChatLexicsCutter.h@@ -0,0 +1,67 @@+/* + * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>+ *+ * 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, write to the Free Software+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA+ */++#ifndef MANGOSSERVER_CHATLEXICSCUTTER_H+#define MANGOSSERVER_CHATLEXICSCUTTER_H++typedef std::vector< std::string > LC_AnalogVector;+typedef std::map< std::string, LC_AnalogVector > LC_AnalogMap;+typedef std::set< std::string > LC_LetterSet;+typedef std::vector< LC_LetterSet > LC_WordVector;+typedef std::vector< LC_WordVector > LC_WordList;+typedef std::multimap< std::string, unsigned int > LC_WordMap;++static int trailingBytesForUTF8[256] = {+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5+};++class LexicsCutter+{+    protected:+        LC_AnalogMap AnalogMap;+        LC_WordList WordList;+        LC_WordMap WordMap;++        std::string InvalidChars;++    public:+        LexicsCutter();++        static bool ReadUTF8(std::string& in, std::string& out, unsigned int& pos);++        std::string trim(std::string& s, const std::string& drop = " ");+        bool Read_Letter_Analogs(std::string& FileName);+        bool Read_Innormative_Words(std::string& FileName);+        void Map_Innormative_Words();+        bool Compare_Word(std::string& str, unsigned int pos, LC_WordVector word);+        bool Check_Lexics(std::string& Phrase);+        +        std::vector< std::pair< unsigned int, unsigned int > > Found;+        bool IgnoreMiddleSpaces;+        bool IgnoreLetterRepeat;+};++#endif+diff --git a/src/game/ChatLog.cpp b/src/game/ChatLog.cppnew file mode 100644index 0000000..2871b6f--- /dev/null+++ b/src/game/ChatLog.cpp@@ -0,0 +1,785 @@+/* + * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>+ *+ * 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, write to the Free Software+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA+ */++#include "Common.h"+#include "ChatLexicsCutter.h"+#include "ChatLog.h"+#include "Chat.h"+#include "Group.h"+#include "Guild.h"+#include "ObjectMgr.h"+#include "SpellAuras.h"+#include "Policies/SingletonImp.h"+#include "Config/ConfigEnv.h"++INSTANTIATE_SINGLETON_1( ChatLog );++ChatLog::ChatLog()+{+    for (int i = 0; i <= CHATLOG_CHAT_TYPES_COUNT - 1; i++)+    {+        names[i] = "";+        files[i] = NULL;+    }+    +    Lexics = NULL;+    fn_innormative = "";+    f_innormative = NULL;+    +    Initialize();+}++ChatLog::~ChatLog()+{+    // close all files (avoiding double-close)+    CloseAllFiles();++    if (Lexics)+    {+        delete Lexics;+        Lexics = NULL;+    }+}++void ChatLog::Initialize()+{+    // determine, if the chat logs are enabled+    ChatLogEnable = sConfig.GetBoolDefault("ChatLogEnable", false);+    ChatLogDateSplit = sConfig.GetBoolDefault("ChatLogDateSplit", false);+    ChatLogUTFHeader = sConfig.GetBoolDefault("ChatLogUTFHeader", false);+    ChatLogIgnoreUnprintable = sConfig.GetBoolDefault("ChatLogIgnoreUnprintable", false);+    +    if (ChatLogEnable)+    {+        // read chat log file names+        names[CHAT_LOG_CHAT] = sConfig.GetStringDefault("ChatLogChatFile", "");+        names[CHAT_LOG_PARTY] = sConfig.GetStringDefault("ChatLogPartyFile", "");+        names[CHAT_LOG_GUILD] = sConfig.GetStringDefault("ChatLogGuildFile", "");+        names[CHAT_LOG_WHISPER] = sConfig.GetStringDefault("ChatLogWhisperFile", "");+        names[CHAT_LOG_CHANNEL] = sConfig.GetStringDefault("ChatLogChannelFile", "");+        names[CHAT_LOG_RAID] = sConfig.GetStringDefault("ChatLogRaidFile", "");+        names[CHAT_LOG_BATTLEGROUND] = sConfig.GetStringDefault("ChatLogBattleGroundFile", "");++        // read screen log flags+        screenflag[CHAT_LOG_CHAT] = sConfig.GetBoolDefault("ChatLogChatScreen", false);+        screenflag[CHAT_LOG_PARTY] = sConfig.GetBoolDefault("ChatLogPartyScreen", false);+        screenflag[CHAT_LOG_GUILD] = sConfig.GetBoolDefault("ChatLogGuildScreen", false);+        screenflag[CHAT_LOG_WHISPER] = sConfig.GetBoolDefault("ChatLogWhisperScreen", false);+        screenflag[CHAT_LOG_CHANNEL] = sConfig.GetBoolDefault("ChatLogChannelScreen", false);+        screenflag[CHAT_LOG_RAID] = sConfig.GetBoolDefault("ChatLogRaidScreen", false);+        screenflag[CHAT_LOG_BATTLEGROUND] = sConfig.GetBoolDefault("ChatLogBattleGroundScreen", false);+    }++    // lexics cutter+    LexicsCutterEnable = sConfig.GetBoolDefault("LexicsCutterEnable", false);++    if (LexicsCutterEnable)+    {+        // initialize lexics cutter parameters+        LexicsCutterInnormativeCut = sConfig.GetBoolDefault("LexicsCutterInnormativeCut", true);+        LexicsCutterNoActionOnGM = sConfig.GetBoolDefault("LexicsCutterNoActionOnGM", true);+        LexicsCutterScreenLog = sConfig.GetBoolDefault("LexicsCutterScreenLog", false);+        LexicsCutterCutReplacement = sConfig.GetStringDefault("LexicsCutterCutReplacement", "&!@^%!^&*!!! [gibberish]");+        LexicsCutterAction = sConfig.GetIntDefault("LexicsCutterAction", 0);+        LexicsCutterActionDuration = sConfig.GetIntDefault("LexicsCutterActionDuration", 60000);+        std::string fn_analogsfile = sConfig.GetStringDefault("LexicsCutterAnalogsFile", "");+        std::string fn_wordsfile = sConfig.GetStringDefault("LexicsCutterWordsFile", "");++        // read lexics cutter flags+        cutflag[CHAT_LOG_CHAT] = sConfig.GetBoolDefault("LexicsCutInChat", true);+        cutflag[CHAT_LOG_PARTY] = sConfig.GetBoolDefault("LexicsCutInParty", true);+        cutflag[CHAT_LOG_GUILD] = sConfig.GetBoolDefault("LexicsCutInGuild", true);+        cutflag[CHAT_LOG_WHISPER] = sConfig.GetBoolDefault("LexicsCutInWhisper", true);+        cutflag[CHAT_LOG_CHANNEL] = sConfig.GetBoolDefault("LexicsCutInChannel", true);+        cutflag[CHAT_LOG_RAID] = sConfig.GetBoolDefault("LexicsCutInRaid", true);+        cutflag[CHAT_LOG_BATTLEGROUND] = sConfig.GetBoolDefault("LexicsCutInBattleGround", true);++        if (fn_analogsfile == "" || fn_wordsfile == "")+        {+            LexicsCutterEnable = false;+        }+        else+        {+            // initialize lexics cutter+            Lexics = new LexicsCutter;+            if (Lexics) Lexics->Read_Letter_Analogs(fn_analogsfile);+            if (Lexics) Lexics->Read_Innormative_Words(fn_wordsfile);+            if (Lexics) Lexics->Map_Innormative_Words();++            // read additional parameters+            Lexics->IgnoreLetterRepeat = sConfig.GetBoolDefault("LexicsCutterIgnoreRepeats", true);+            Lexics->IgnoreMiddleSpaces = sConfig.GetBoolDefault("LexicsCutterIgnoreSpaces", true);+            fn_innormative = sConfig.GetStringDefault("LexicsCutterLogFile", "");+        }+    }++    // open all files (with aliasing)+    OpenAllFiles();++    // write timestamps (init)+    WriteInitStamps();+}++bool ChatLog::_ChatCommon(int ChatType, Player *player, std::string &msg)+{+    if (LexicsCutterEnable && Lexics && cutflag[ChatType] && Lexics->Check_Lexics(msg)) ChatBadLexicsAction(player, msg);++    if (!ChatLogEnable) return(false);++    if (ChatLogIgnoreUnprintable)+    {+        // have to ignore unprintables, verify string by UTF8 here+        unsigned int pos = 0;+        std::string lchar;+        while (LexicsCutter::ReadUTF8(msg, lchar, pos))+        {+            if (lchar.size() == 1)+            {+                if (lchar[0] < ' ') return(false); // unprintable detected+            }+        }+    }++    return(true);+}+        +void ChatLog::ChatMsg(Player *player, std::string &msg, uint32 type)+{+    if (!_ChatCommon(CHAT_LOG_CHAT, player, msg)) return;++    CheckDateSwitch();++    std::string log_str = "";++    switch (type)+    {+        case CHAT_MSG_EMOTE:+        log_str.append("{EMOTE} ");+        break;++        case CHAT_MSG_YELL:+        log_str.append("{YELL} ");+        break;+    }++    log_str.append("[");+    log_str.append(player->GetName());+    log_str.append("] ");++    log_str.append(msg);++    log_str.append("\n");++    if (screenflag[CHAT_LOG_CHAT]) printf("%s", log_str.c_str());+    if (files[CHAT_LOG_CHAT])+    {+        OutTimestamp(files[CHAT_LOG_CHAT]);+        fprintf(files[CHAT_LOG_CHAT], "%s", log_str.c_str());+        fflush(files[CHAT_LOG_CHAT]);+    }+}++void ChatLog::PartyMsg(Player *player, std::string &msg)+{+    if (!_ChatCommon(CHAT_LOG_PARTY, player, msg)) return;++    CheckDateSwitch();++    std::string log_str = "";++    log_str.append("[");+    log_str.append(player->GetName());+    log_str.append("]->GROUP:");+    +    Group *group = player->GetGroup();+    if (!group)+    {+        log_str.append("[unknown group] ");+    }+    else+    {+        // obtain group information+        log_str.append("[");++        uint8 gm_count = group->GetMembersCount();+        uint8 gm_count_m1 = gm_count - 1;+        uint64 gm_leader_GUID = group->GetLeaderGUID();+        Player *gm_member;++        gm_member = sObjectMgr.GetPlayer(gm_leader_GUID);+        if (gm_member)+        {+            log_str.append(gm_member->GetName());+            log_str.append(",");+        }++        Group::MemberSlotList g_members = group->GetMemberSlots();+        +        for (Group::member_citerator itr = g_members.begin(); itr != g_members.end(); itr++)+        {+            if (itr->guid == gm_leader_GUID) continue;++            gm_member = sObjectMgr.GetPlayer(itr->guid);+            if (gm_member)+            {+                log_str.append(itr->name);+                log_str.append(",");+            }+        }++        log_str.erase(log_str.length() - 1);+        log_str.append("] ");+    }++    log_str.append(msg);++    log_str.append("\n");+    +    if (screenflag[CHAT_LOG_PARTY]) printf("%s", log_str.c_str());+    if (files[CHAT_LOG_PARTY])+    {+        OutTimestamp(files[CHAT_LOG_PARTY]);+        fprintf(files[CHAT_LOG_PARTY], "%s", log_str.c_str());+        fflush(files[CHAT_LOG_PARTY]);+    }+}++void ChatLog::GuildMsg(Player *player, std::string &msg, bool officer)+{+    if (!_ChatCommon(CHAT_LOG_GUILD, player, msg)) return;++    CheckDateSwitch();++    std::string log_str = "";++    log_str.append("[");+    log_str.append(player->GetName());+    log_str.append((officer ? "]->GUILD_OFF:" : "]->GUILD:"));+    +    if (!player->GetGuildId())+    {+        log_str.append("[unknown guild] ");+    }+    else+    {+        Guild *guild = sObjectMgr.GetGuildById(player->GetGuildId());+        if (!guild)+        {+            log_str.append("[unknown guild] ");+        }+        else+        {+            // obtain guild information+            log_str.append("(");+            log_str.append(guild->GetName());+            log_str.append(") ");+        }+    }++    log_str.append(msg);++    log_str.append("\n");+    +    if (screenflag[CHAT_LOG_GUILD]) printf("%s", log_str.c_str());+    if (files[CHAT_LOG_GUILD])+    {+        OutTimestamp(files[CHAT_LOG_GUILD]);+        fprintf(files[CHAT_LOG_GUILD], "%s", log_str.c_str());+        fflush(files[CHAT_LOG_GUILD]);+    }+}++void ChatLog::WhisperMsg(Player *player, std::string &to, std::string &msg)+{+    if (!_ChatCommon(CHAT_LOG_WHISPER, player, msg)) return;++    CheckDateSwitch();++    std::string log_str = "";++    log_str.append("[");+    log_str.append(player->GetName());+    log_str.append("]->");+    +    if (to.size() == 0)+    {+        log_str.append("[???] ");+    }+    else+    {+        normalizePlayerName(to);+        log_str.append("[");+        log_str.append(to);+        log_str.append("] ");+    }+    +    log_str.append(msg);++    log_str.append("\n");+    +    if (screenflag[CHAT_LOG_WHISPER]) printf("%s", log_str.c_str());+    if (files[CHAT_LOG_WHISPER])+    {+        OutTimestamp(files[CHAT_LOG_WHISPER]);+        fprintf(files[CHAT_LOG_WHISPER], "%s", log_str.c_str());+        fflush(files[CHAT_LOG_WHISPER]);+    }+}++void ChatLog::ChannelMsg(Player *player, std::string &channel, std::string &msg)+{+    if (!_ChatCommon(CHAT_LOG_CHANNEL, player, msg)) return;++    CheckDateSwitch();++    std::string log_str = "";++    log_str.append("[");+    log_str.append(player->GetName());+    log_str.append("]->CHANNEL:");+    +    if (channel.size() == 0)+    {+        log_str.append("[unknown channel] ");+    }+    else+    {+        log_str.append("[");+        log_str.append(channel);+        log_str.append("] ");+    }+    +    log_str.append(msg);++    log_str.append("\n");++    if (screenflag[CHAT_LOG_CHANNEL]) printf("%s", log_str.c_str());+    if (files[CHAT_LOG_CHANNEL])+    {+        OutTimestamp(files[CHAT_LOG_CHANNEL]);+        fprintf(files[CHAT_LOG_CHANNEL], "%s", log_str.c_str());+        fflush(files[CHAT_LOG_CHANNEL]);+    }+}++void ChatLog::RaidMsg(Player *player, std::string &msg, uint32 type)+{+    if (!_ChatCommon(CHAT_LOG_RAID, player, msg)) return;++    CheckDateSwitch();++    std::string log_str = "";++    log_str.append("[");+    log_str.append(player->GetName());++    switch (type)+    {+        case CHAT_MSG_RAID:+        log_str.append("]->RAID:");+        break;++        case CHAT_MSG_RAID_LEADER:+        log_str.append("]->RAID_LEADER:");+        break;++        case CHAT_MSG_RAID_WARNING:+        log_str.append("]->RAID_WARN:");+        break;++        default:+        log_str.append("]->RAID_UNKNOWN:");+    }+    +    Group *group = player->GetGroup();+    if (!group)+    {+        log_str.append("[unknown raid] ");+    }+    else+    {+        // obtain group information+        log_str.append("[");++        uint8 gm_count = group->GetMembersCount();+        uint8 gm_count_m1 = gm_count - 1;+        uint64 gm_leader_GUID = group->GetLeaderGUID();+        Player *gm_member;++        gm_member = sObjectMgr.GetPlayer(gm_leader_GUID);+        if (gm_member)+        {+            log_str.append(gm_member->GetName());+            log_str.append(",");+        }++        Group::MemberSlotList g_members = group->GetMemberSlots();+    +        for (Group::member_citerator itr = g_members.begin(); itr != g_members.end(); itr++)+        {+            if (itr->guid == gm_leader_GUID) continue;++            gm_member = sObjectMgr.GetPlayer(itr->guid);+            if (gm_member)+            {+                log_str.append(itr->name);+                log_str.append(",");+            }+        }+    +        log_str.erase(log_str.length() - 1);+        log_str.append("] ");+    }++    log_str.append(msg);++    log_str.append("\n");++    if (screenflag[CHAT_LOG_RAID]) printf("%s", log_str.c_str());+    if (files[CHAT_LOG_RAID])+    {+        OutTimestamp(files[CHAT_LOG_RAID]);+        fprintf(files[CHAT_LOG_RAID], "%s", log_str.c_str());+        fflush(files[CHAT_LOG_RAID]);+    }+}++void ChatLog::BattleGroundMsg(Player *player, std::string &msg, uint32 type)+{+    if (!_ChatCommon(CHAT_LOG_BATTLEGROUND, player, msg)) return;++    CheckDateSwitch();++    std::string log_str = "";++    log_str.append("[");+    log_str.append(player->GetName());++    switch (type)+    {+        case CHAT_MSG_BATTLEGROUND:+        log_str.append("]->BG:");+        break;++        case CHAT_MSG_BATTLEGROUND_LEADER:+        log_str.append("]->BG_LEADER:");+        break;++        default:+        log_str.append("]->BG_UNKNOWN:");+    }+    +    Group *group = player->GetGroup();+    if (!group)+    {+        log_str.append("[unknown group] ");+    }+    else+    {+        // obtain group information+        log_str.append("[");++        uint8 gm_count = group->GetMembersCount();+        uint8 gm_count_m1 = gm_count - 1;+        uint64 gm_leader_GUID = group->GetLeaderGUID();+        Player *gm_member;++        gm_member = sObjectMgr.GetPlayer(gm_leader_GUID);+        if (gm_member)+        {+            log_str.append(gm_member->GetName());+            log_str.append(",");+        }++        Group::MemberSlotList g_members = group->GetMemberSlots();+    +        for (Group::member_citerator itr = g_members.begin(); itr != g_members.end(); itr++)+        {+            if (itr->guid == gm_leader_GUID) continue;++            gm_member = sObjectMgr.GetPlayer(itr->guid);+            if (gm_member)+            {+                log_str.append(itr->name);+                log_str.append(",");+            }+        }+    +        log_str.erase(log_str.length() - 1);+        log_str.append("] ");+    }++    log_str.append(msg);++    log_str.append("\n");++    if (screenflag[CHAT_LOG_BATTLEGROUND]) printf("%s", log_str.c_str());+    if (files[CHAT_LOG_BATTLEGROUND])+    {+        OutTimestamp(files[CHAT_LOG_BATTLEGROUND]);+        fprintf(files[CHAT_LOG_BATTLEGROUND], "%s", log_str.c_str());+        fflush(files[CHAT_LOG_BATTLEGROUND]);+    }+}++void ChatLog::OpenAllFiles()+{+    std::string tempname;+    char dstr[12];++    if (ChatLogDateSplit)+    {+        time_t t = time(NULL);+        tm* aTm = localtime(&t);+        sprintf(dstr, "%-4d-%02d-%02d", aTm->tm_year + 1900, aTm->tm_mon + 1, aTm->tm_mday);+    }++    if (ChatLogEnable)+    {+        for (int i = 0; i <= CHATLOG_CHAT_TYPES_COUNT - 1; i++)+        {+            if (names[i] != "")+            {+                for (int j = i - 1; j >= 0; j--)+                {+                    if (names[i] == names[j])+                    {+                        files[i] = files[j];+                        break;+                    }+                }+                if (!files[i])+                {+                    tempname = names[i];+                    if (ChatLogDateSplit)+                    {+                        // append date instead of $d if applicable+                        int dpos = tempname.find("$d");+                        if (dpos != tempname.npos)+                        {+                            tempname.replace(dpos, 2, &dstr[0], 10);+                        }+                    }+                    files[i] = fopen(tempname.c_str(), "a+b");+                    if (ChatLogUTFHeader && (ftell(files[i]) == 0)) fputs("\xEF\xBB\xBF", files[i]);+                }+            }+        }+    }++    // initialize innormative log+    if (LexicsCutterEnable)+    {+        if (fn_innormative != "")+        {+            tempname = fn_innormative;+            if (ChatLogDateSplit)+            {+                // append date instead of $d if applicable+                int dpos = tempname.find("$d");+                if (dpos != tempname.npos)+                {+                    tempname.replace(dpos, 2, &dstr[0], 10);+                }+            }+            f_innormative = fopen(tempname.c_str(), "a+b");+            if (ChatLogUTFHeader && (ftell(f_innormative) == 0)) fputs("\xEF\xBB\xBF", f_innormative);+        }+    }+}++void ChatLog::CloseAllFiles()+{+    for (int i = 0; i <= CHATLOG_CHAT_TYPES_COUNT - 1; i++)+    {+        if (files[i])+        {+            for (int j = i + 1; j <= CHATLOG_CHAT_TYPES_COUNT - 1; j++)+            {+                if (files[j] == files[i]) files[j] = NULL;+            }+        +            fclose(files[i]);+            files[i] = NULL;+        }+    }++    if (f_innormative)+    {+        fclose(f_innormative);+        f_innormative = NULL;+    }+}++void ChatLog::CheckDateSwitch()+{+    if (ChatLogDateSplit)+    {+        time_t t = time(NULL);+        tm* aTm = localtime(&t);+        if (lastday != aTm->tm_mday)+        {+            // date switched+            CloseAllFiles();+            OpenAllFiles();+            WriteInitStamps();+        }+    }+}++void ChatLog::WriteInitStamps()+{+    // remember date+    time_t t = time(NULL);+    tm* aTm = localtime(&t);+    lastday = aTm->tm_mday;++    if (files[CHAT_LOG_CHAT])+    {+        OutTimestamp(files[CHAT_LOG_CHAT]);+        fprintf(files[CHAT_LOG_CHAT], "%s", "[SYSTEM] Chat Log Initialized\n");+    }+    if (files[CHAT_LOG_PARTY])+    {+        OutTimestamp(files[CHAT_LOG_PARTY]);+        fprintf(files[CHAT_LOG_PARTY], "%s", "[SYSTEM] Party Chat Log Initialized\n");+    }+    if (files[CHAT_LOG_GUILD])+    {+        OutTimestamp(files[CHAT_LOG_GUILD]);+        fprintf(files[CHAT_LOG_GUILD], "%s", "[SYSTEM] Guild Chat Log Initialized\n");+    }+    if (files[CHAT_LOG_WHISPER])+    {+        OutTimestamp(files[CHAT_LOG_WHISPER]);+        fprintf(files[CHAT_LOG_WHISPER], "%s", "[SYSTEM] Whisper Log Initialized\n");+    }+    if (files[CHAT_LOG_CHANNEL])+    {+        OutTimestamp(files[CHAT_LOG_CHANNEL]);+        fprintf(files[CHAT_LOG_CHANNEL], "%s", "[SYSTEM] Chat Channels Log Initialized\n");+    }+    if (files[CHAT_LOG_RAID])+    {+        OutTimestamp(files[CHAT_LOG_RAID]);+        fprintf(files[CHAT_LOG_RAID], "%s", "[SYSTEM] Raid Party Chat Log Initialized\n");+    }++    if (f_innormative)+    {+        OutTimestamp(f_innormative);+        fprintf(f_innormative, "%s", "[SYSTEM] Innormative Lexics Log Initialized\n");+    }+}++void ChatLog::OutTimestamp(FILE* file)+{+    time_t t = time(NULL);+    tm* aTm = localtime(&t);+    fprintf(file, "%-4d-%02d-%02d %02d:%02d:%02d ", aTm->tm_year + 1900, aTm->tm_mon + 1, aTm->tm_mday, aTm->tm_hour, aTm->tm_min, aTm->tm_sec);+}++void ChatLog::ChatBadLexicsAction(Player* player, std::string& msg)+{+    // logging+    std::string log_str = "";++    log_str.append("[");+    log_str.append(player->GetName());+    log_str.append("] ");++    log_str.append(msg);++    log_str.append("\n");++    if (LexicsCutterScreenLog) printf("<INNORMATIVE!> %s", log_str.c_str());+    if (f_innormative)+    {+        OutTimestamp(f_innormative);+        fprintf(f_innormative, "%s", log_str.c_str());+        fflush(f_innormative);+    }++    // cutting innormative lexics+    if (LexicsCutterInnormativeCut)+    {+        msg = LexicsCutterCutReplacement;+    }++    if (!player || !player->GetSession()) return;++    if (LexicsCutterNoActionOnGM && player->GetSession()->GetSecurity()) return;++    switch (LexicsCutterAction)+    {+        case LEXICS_ACTION_SHEEP:+        {+            // sheep me, yeah, yeah, sheep me+            player->CastSpell(player, 118, true);+        }+        break;++        case LEXICS_ACTION_STUN:+        {+            // stunned surprised+            player->CastSpell(player, 13005, true);+        }+        break;++        case LEXICS_ACTION_DIE:+        {+            // oops, kicked the bucket+            player->DealDamage(player, player->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);+        }+        break;++        case LEXICS_ACTION_DRAIN:+        {+            // living corpse :)+            player->DealDamage(player, player->GetHealth() - 5, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);+        }+        break;+++        case LEXICS_ACTION_SILENCE:+        {+            // glue the mouth+            time_t mutetime = time(NULL) + (int) (LexicsCutterActionDuration / 1000);+            player->GetSession()->m_muteTime = mutetime;+        }+        break;++        case LEXICS_ACTION_STUCK:+        {+            // yo, the Matrix has had you :) [by KAPATEJIb]+            player->CastSpell(player, 23312, true);+        }+        break;++        case LEXICS_ACTION_SICKNESS:+        {+            // for absence of censorship, there is punishment [by Koshei]+            player->CastSpell(player, 15007, true);+        }+        break;++        default:+        // no action except logging+        break;+    }+}diff --git a/src/game/ChatLog.h b/src/game/ChatLog.hnew file mode 100644index 0000000..342d71d--- /dev/null+++ b/src/game/ChatLog.h@@ -0,0 +1,107 @@+/* + * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>+ *+ * 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, write to the Free Software+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA+ */++#ifndef MANGOSSERVER_CHATLOG_H+#define MANGOSSERVER_CHATLOG_H++#include "SharedDefines.h"+#include "ChatLexicsCutter.h"+#include "ObjectMgr.h"+#include "Policies/Singleton.h"++#define CHATLOG_CHAT_TYPES_COUNT 7++enum ChatLogFiles+{+    CHAT_LOG_CHAT = 0,+    CHAT_LOG_PARTY = 1,+    CHAT_LOG_GUILD = 2,+    CHAT_LOG_WHISPER = 3,+    CHAT_LOG_CHANNEL = 4,+    CHAT_LOG_RAID = 5,+    CHAT_LOG_BATTLEGROUND = 6,+};++enum LexicsActions+{+    LEXICS_ACTION_LOG = 0,+    LEXICS_ACTION_SHEEP = 1,+    LEXICS_ACTION_STUN = 2,+    LEXICS_ACTION_DIE = 3,+    LEXICS_ACTION_DRAIN = 4,+    LEXICS_ACTION_SILENCE = 5,+    LEXICS_ACTION_STUCK = 6,+    LEXICS_ACTION_SICKNESS = 7,+};++class ChatLog : public MaNGOS::Singleton<ChatLog, MaNGOS::ClassLevelLockable<ChatLog, ACE_Thread_Mutex> >+{+    public:+        ChatLog();+        ~ChatLog();++        void Initialize();+        +        void ChatMsg(Player *player, std::string &msg, uint32 type);+        void PartyMsg(Player *player, std::string &msg);+        void GuildMsg(Player *player, std::string &msg, bool officer);+        void WhisperMsg(Player *player, std::string &to, std::string &msg);+        void ChannelMsg(Player *player, std::string &channel, std::string &msg);+        void RaidMsg(Player *player, std::string &msg, uint32 type);+        void BattleGroundMsg(Player *player, std::string &msg, uint32 type);+        +        void ChatBadLexicsAction(Player *player, std::string &msg);+        +    private:+        bool _ChatCommon(int ChatType, Player *player, std::string &msg);++        bool ChatLogEnable;+        bool ChatLogDateSplit;+        bool ChatLogUTFHeader;+        bool ChatLogIgnoreUnprintable;++        int lastday;+   +        FILE* files[CHATLOG_CHAT_TYPES_COUNT];+        std::string names[CHATLOG_CHAT_TYPES_COUNT];+        bool screenflag[CHATLOG_CHAT_TYPES_COUNT];+   +        LexicsCutter* Lexics;+        bool cutflag[CHATLOG_CHAT_TYPES_COUNT];++        bool LexicsCutterEnable;+        bool LexicsCutterInnormativeCut;+        bool LexicsCutterNoActionOnGM;+        bool LexicsCutterScreenLog;+        std::string LexicsCutterCutReplacement;+        int LexicsCutterAction;+        int LexicsCutterActionDuration;+        std::string fn_innormative;+        FILE* f_innormative;++        void OpenAllFiles();+        void CloseAllFiles();+        void CheckDateSwitch();++        void WriteInitStamps();+        void OutTimestamp(FILE *file);+};++#define sChatLog MaNGOS::Singleton<ChatLog>::Instance()+#endif+