# Date: 2014-3-18
# Fixed: SymbolixDEV
# Status: Untested
# Compile: Untested
# Working: Untested
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/game/Scripting/ScriptLoader.cpp
--- a/src/server/game/Scripting/ScriptLoader.cpp Wed Apr 27 02:04:17 2011 +0400
+++ b/src/server/game/Scripting/ScriptLoader.cpp Wed Apr 27 02:46:43 2011 +0400
@@ -591,7 +591,7 @@
void AddSC_outdoorpvp_zm();
// player
-void AddSC_chat_log();
+void AddSC_lexics_chat_log();
#endif
@@ -677,7 +677,7 @@
AddSC_npc_taxi();
AddSC_achievement_scripts();
AddSC_script_bot_giver();
- AddSC_chat_log();
+ AddSC_lexics_chat_log();
#endif
}
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/scripts/World/CMakeLists.txt
--- a/src/server/scripts/World/CMakeLists.txt Wed Apr 27 02:04:17 2011 +0400
+++ b/src/server/scripts/World/CMakeLists.txt Wed Apr 27 02:46:43 2011 +0400
@@ -6,7 +6,6 @@
World/boss_lethon.cpp
World/boss_taerar.cpp
World/boss_ysondre.cpp
- World/chat_log.cpp
World/go_scripts.cpp
World/guards.cpp
World/item_scripts.cpp
@@ -15,6 +14,8 @@
World/npc_professions.cpp
World/npc_taxi.cpp
World/npcs_special.cpp
+ World/ChatLog/ChatLog.cpp
+ World/ChatLog/ChatLexicsCutter.cpp
)
message(" -> Prepared: World")
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/scripts/World/ChatLog/ChatLexicsCutter.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/scripts/World/ChatLog/ChatLexicsCutter.cpp Wed Apr 27 02:46:43 2011 +0400
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS
+ *
+ * Copyright (C) 2008-2010 Trinity
+ *
+ * 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(const std::string& sAnalogsFileName, const std::string& sInnormativeWordsFileName, bool bIgnoreMiddleSpaces, bool bIgnoreLetterRepeat)
+ : m_sInvalidChars("~`!@#$%^&*()-_+=[{]}|\\;:'\",<.>/?"), m_bIgnoreMiddleSpaces(bIgnoreMiddleSpaces), m_bIgnoreLetterRepeat(bIgnoreLetterRepeat)
+{
+ if (!_ReadLetterAnalogs(sAnalogsFileName))
+ TC_LOG_ERROR("network" Unable to open file with letter analogs '%s'", sAnalogsFileName);
+ if (!_ReadInnormativeWords(sInnormativeWordsFileName))
+ TC_LOG_ERROR("network" Unable to open file with innormative words '%s'", sInnormativeWordsFileName);
+ _MapInnormativeWords();
+}
+
+bool LexicsCutter::ReadUTF8(const 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;
+}
+
+inline void LexicsCutter::_Trim(std::string& s, const std::string& drop) const
+{
+ s.erase(s.find_last_not_of(drop) + 1);
+ s.erase(0, s.find_first_not_of(drop));
+}
+
+bool LexicsCutter::_ProcessLine(char* szLine, std::string& sLine) const
+{
+ // Check for UTF8 prefix and comments
+ if (strlen(szLine) >= 3)
+ if (szLine[0] == '\xEF' && szLine[1] == '\xBB' && szLine[2] == '\xBF')
+ strncpy(&szLine[0], &szLine[3], strlen(szLine) - 3);
+
+ if (strlen(szLine) >= 2)
+ if (szLine[0] == '/' && szLine[1] == '/')
+ return false;
+
+ // Check for empty string
+ sLine = szLine;
+ _Trim(sLine, "\x0A\x0D\x20");
+ if (sLine.empty())
+ return false;
+
+ // Process line without CR/LF
+ sLine = szLine;
+ _Trim(sLine, "\x0A\x0D");
+ return true;
+}
+
+bool LexicsCutter::_ReadLetterAnalogs(const std::string& fileName)
+{
+ char szLine[1024];
+
+ FILE* file = fopen(fileName.c_str(), "rb");
+ if (!file)
+ return false;
+
+ while (!feof(file))
+ {
+ szLine[0] = 0x0;
+ fgets(szLine, 1020, file);
+
+ std::string sLine;
+ if (!_ProcessLine(szLine, sLine))
+ continue;
+
+ std::string sChar;
+ unsigned int pos = 0;
+ if (ReadUTF8(sLine, sChar, pos))
+ {
+ // Create analogs vector
+ std::string sAnalog;
+ LC_AnalogVector av;
+ while (ReadUTF8(sLine, sAnalog, pos))
+ av.push_back(sAnalog);
+
+ // Store vector in hash map
+ m_AnalogMap[sChar] = av;
+ }
+ }
+ fclose(file);
+ return true;
+}
+
+bool LexicsCutter::_ReadInnormativeWords(const std::string& fileName)
+{
+ char szLine[1024];
+
+ FILE* file = fopen(fileName.c_str(), "rb");
+ if (!file)
+ return false;
+
+ while (!feof(file))
+ {
+ szLine[0] = 0x0;
+ fgets(szLine, 1020, file);
+
+ std::string sLine;
+ if (!_ProcessLine(szLine, sLine))
+ continue;
+
+ // Create word vector of vectors
+ LC_WordVector vw;
+ std::string sChar;
+ unsigned int pos = 0;
+ while (ReadUTF8(sLine, sChar, pos))
+ {
+ LC_LetterSet vl;
+
+ // Initialize letter set with letter read
+ vl.insert(sChar);
+
+ // Find letter analogs and push them onto the vector
+ LC_AnalogMap::iterator itr = m_AnalogMap.find(sChar);
+ if (itr != m_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
+ m_WordList.push_back(vw);
+ }
+ fclose(file);
+ return true;
+}
+
+void LexicsCutter::_MapInnormativeWords()
+{
+ // Process all the words in the vector
+ for (uint32 i = 0; i < m_WordList.size(); ++i)
+ // Parse all analogs in the first word letter
+ for (LC_LetterSet::iterator itr = (*m_WordList[i].begin()).begin(); itr != (*m_WordList[i].begin()).end(); ++itr)
+ // Map the word to its first letter variants
+ m_WordMap.insert(std::pair (*itr, i));
+}
+
+bool LexicsCutter::_CompareWord(const std::string& str, unsigned int pos, LC_WordVector word) const
+{
+ std::string sCharPrev;
+ std::string sChar;
+
+ // Read first letter of the word into lchar_prev
+ ReadUTF8(str, sChar, pos);
+
+ // Compare word //SymbolixDEV
+ // 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, sChar, pos))
+ return false;
+ // Check, if the letter is in the set
+ LC_LetterSet ls = *i;
+ if (ls.count(sChar) == 0)
+ {
+ // Letter is not in set, but we must check, if it is not space or repeat
+ if ((!(m_bIgnoreMiddleSpaces && (sChar == " "))) &&
+ (!(m_bIgnoreLetterRepeat && (sChar == sCharPrev))))
+ {
+ // 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 (m_bIgnoreLetterRepeat)
+ sCharPrev = sChar;
+ }
+ return true;
+}
+
+bool LexicsCutter::CheckLexics(const std::string& msg)
+{
+ std::string sChar;
+ LC_WordMap::iterator i;
+ std::pair ii;
+
+ if (msg.size() == 0)
+ return false;
+
+ // Remove links |cffffffff|H:|h[]|h|r
+ std::string s(msg);
+ unsigned int offset = 0;
+ unsigned int start = -1;
+ while ((start = s.find("|cffffffff|H", offset)) != -1)
+ {
+ unsigned int end = s.find("|h|r", start);
+ if (end == -1)
+ break;
+
+ s = s.replace(start, end + 4 - start, "");
+ offset = start;
+ }
+
+ // 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(s, sChar, pos))
+ if (m_sInvalidChars.find(sChar) == std::string::npos)
+ str.append(sChar);
+
+ // String prepared, now parse it and scan for all the words
+ unsigned int pos_prev = 0;
+ pos = 0;
+ while (ReadUTF8(str, sChar, pos))
+ {
+ // Got character, now try to find wordmap for it
+ ii = m_WordMap.equal_range(sChar);
+ // Iterate over all found words
+ for (i = ii.first; i != ii.second; i++)
+ // Compare word at initial position
+ if (_CompareWord(str, pos_prev, m_WordList[i->second]))
+ return true;
+ // Set initial position to the current position
+ pos_prev = pos;
+ }
+ return false;
+}
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/scripts/World/ChatLog/ChatLexicsCutter.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/scripts/World/ChatLog/ChatLexicsCutter.h Wed Apr 27 02:46:43 2011 +0400
@@ -0,0 +1,70 @@
+/* //SymbolixDEV
+ * Copyright (C) 2005-2009 MaNGOS
+ *//SymbolixDEV
+ * Copyright (C) 2008-2010 Trinity
+ *//SymbolixDEV
+ * 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.
+ *//SymbolixDEV
+ * 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
+ */
+//SymbolixDEV
+#ifndef TRINITY_CHATLEXICSCUTTER_H
+#define TRINITY_CHATLEXICSCUTTER_H
+//SymbolixDEV
+typedef std::vector LC_AnalogVector;
+typedef std::map LC_AnalogMap;
+typedef std::set LC_LetterSet;
+typedef std::vector LC_WordVector;
+typedef std::vector LC_WordList;
+typedef std::multimap LC_WordMap;
+//SymbolixDEV
+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
+};
+//SymbolixDEV//SymbolixDEV//SymbolixDEVV//SymbolixDEVV//SymbolixDEVVV//SymbolixDEVV//SymbolixDEVVV
+class LexicsCutter
+{
+protected:
+ LC_AnalogMap m_AnalogMap;
+ LC_WordList m_WordList;
+ LC_WordMap m_WordMap;
+//SymbolixDEV
+ std::string m_sInvalidChars;
+ bool m_bIgnoreMiddleSpaces;
+ bool m_bIgnoreLetterRepeat;
+//SymbolixDEV
+ void _Trim(std::string& s, const std::string& drop = " ") const;
+ bool _CompareWord(const std::string& str, unsigned int pos, LC_WordVector word) const;
+ bool _ProcessLine(char* szLine, std::string& sLine) const;
+//SymbolixDEV
+ bool _ReadLetterAnalogs(const std::string& fileName);
+ bool _ReadInnormativeWords(const std::string& fileName);
+ void _MapInnormativeWords();
+//SymbolixDEV
+public:
+ LexicsCutter(const std::string& sAnalogsFileName, const std::string& sInnormativeWordsFileName, bool bIgnoreMiddleSpaces, bool bIgnoreLetterRepeat);
+//SymbolixDEV
+ static bool ReadUTF8(const std::string& in, std::string& out, unsigned int& pos);
+ //SymbolixDEV
+ bool CheckLexics(const std::string& phrase);
+};
+
+#endif
+
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/scripts/World/ChatLog/ChatLog.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/scripts/World/ChatLog/ChatLog.cpp Wed Apr 27 02:46:43 2011 +0400
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS
+ *
+ * Copyright (C) 2008-2014 Trinity
+ * SymbolixDEV
+ * 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.
+ * SymbolixDEV
+ * 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.
+ * SymbolixDEV
+ * 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
+ */
+ // SymbolixDEV
+#include "Common.h"
+#include "ChatLexicsCutter.h"
+#include "ChatLog.h"
+#include "Chat.h"
+#include "Group.h"
+#include "Guild.h"
+#include "Channel.h"
+#include "ObjectMgr.h"
+#include "SpellAuras.h"
+#include "Config.h"
+
+ChatLogInfo::ChatLogInfo(ChatLogType type, bool bChat, bool bLexics) :
+ m_file(NULL), m_screenFlag(false), m_cutFlag(false), m_type(type)
+{
+ std::string sType = ChatLog::GetChatNameByType(type);
+ if (bChat)
+ {
+ m_name = sConfig->GetStringDefault(std::string("ChatLog." + sType + ".File").c_str(), "");
+ m_screenFlag = sConfig->GetBoolDefault(std::string("ChatLog." + sType + ".Screen").c_str(), false);
+ }
+
+ if (bLexics)
+ m_cutFlag = sConfig->GetBoolDefault(std::string("ChatLog.Lexics." + sType + ".Cut").c_str(), true);
+}
+
+void ChatLogInfo::OpenFile(bool bDateSplit, const std::string& sDate, bool bUTFHeader)
+{
+ if (!m_name.empty() && !m_file)
+ {
+ std::string tmp(m_name);
+ if (bDateSplit)
+ {
+ // Replace $d with date value if applicable
+ int dpos = tmp.find("$d");
+ if (dpos != tmp.npos)
+ tmp.replace(dpos, 2, sDate.c_str(), sDate.size());
+ }
+ m_file = fopen(tmp.c_str(), "a+b");
+ if (m_file)
+ {
+ if (bUTFHeader && ftell(m_file) == 0)
+ fputs("\xEF\xBB\xBF", m_file);
+
+ std::string s("[SYSTEM] " + ChatLog::GetChatDescByType(m_type) + " Log Initialized\n");
+ WriteFile(s);
+ }
+ }
+}
+
+void ChatLogInfo::WriteFile(const std::string& msg)
+{
+ ACE_Guard guard(m_lock);
+ if (m_file)
+ {
+ ChatLog::OutTimestamp(m_file);
+ fprintf(m_file, "%s\n", msg.c_str());
+ fflush(m_file);
+ }
+}
+
+std::string ChatLog::GetChatNameByType(ChatLogType type)
+{
+ switch (type)
+ {
+ case CHAT_LOG_CHAT: return "Chat";
+ case CHAT_LOG_PARTY: return "Party";
+ case CHAT_LOG_GUILD: return "Guild";
+ case CHAT_LOG_WHISPER: return "Whisper";
+ case CHAT_LOG_CHANNEL: return "Channel";
+ case CHAT_LOG_RAID: return "Raid";
+ case CHAT_LOG_BATTLEGROUND: return "BattleGround";
+ case CHAT_LOG_INNORMATIVE: return "Lexics.Innormative";
+ default: return "Unknown";
+ }
+}
+
+std::string ChatLog::GetChatDescByType(ChatLogType type)
+{
+ switch (type)
+ {
+ case CHAT_LOG_CHAT: return "Chat";
+ case CHAT_LOG_PARTY: return "Party Chat";
+ case CHAT_LOG_GUILD: return "Guild Chat";
+ case CHAT_LOG_WHISPER: return "Whisper";
+ case CHAT_LOG_CHANNEL: return "Channels";
+ case CHAT_LOG_RAID: return "Raid Chat";
+ case CHAT_LOG_BATTLEGROUND: return "Battleground Chat";
+ case CHAT_LOG_INNORMATIVE: return "Lexics Innormative";
+ default: return "Unknown";
+ }
+}
+
+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);
+}
+
+ChatLog::ChatLog() : PlayerScript("LexicsChatLog"), m_pLexics(NULL), m_pInnormative(NULL)
+{
+ _Initialize();
+}
+
+ChatLog::~ChatLog()
+{
+ // Close all files (avoiding double-close)
+ _CloseAllFiles();
+
+ if (m_pLexics)
+ {
+ delete m_pLexics;
+ m_pLexics = NULL;
+ }
+ for (uint32 i = CHAT_LOG_CHAT; i < CHAT_LOG_COUNT; i++)
+ delete m_pLogs[i];
+}
+
+void ChatLog::_Initialize()
+{
+ // Load config settings
+ m_bChatLogEnable = sConfig->GetBoolDefault("ChatLog.Enable", true);
+ m_bChatLogDateSplit = sConfig->GetBoolDefault("ChatLog.DateSplit", true);
+ m_bChatLogUTFHeader = sConfig->GetBoolDefault("ChatLog.UTFHeader", true);
+ m_bChatLogIgnoreUnprintable = sConfig->GetBoolDefault("ChatLog.Ignore.Unprintable", true);
+
+ m_bLexicsEnable = sConfig->GetBoolDefault("ChatLog.Lexics.Enable", true);
+ if (m_bLexicsEnable)
+ {
+ std::string sAnalogsFileName = sConfig->GetStringDefault("ChatLog.Lexics.AnalogsFile", "");
+ std::string sInnormativeWordsFileName = sConfig->GetStringDefault("ChatLog.Lexics.WordsFile", "");
+
+ m_pInnormative = new ChatLogInfo(CHAT_LOG_INNORMATIVE, true, false);
+ if (sAnalogsFileName.empty() || sInnormativeWordsFileName.empty())
+ m_bLexicsEnable = false;
+ else
+ {
+ // Initialize lexics cutter parameters
+ m_bLexicsInnormativeCut = sConfig->GetBoolDefault("ChatLog.Lexics.Cut.Enable", true);
+ m_sLexicsCutReplacement = sConfig->GetStringDefault("ChatLog.Lexics.Cut.Replacement", "&!@^%!^&*!!!");
+ m_LexicsAction = LexicsActions(sConfig->GetIntDefault("ChatLog.Lexics.Action", LEXICS_ACTION_LOG));
+ m_unLexicsActionDuration = sConfig->GetIntDefault("ChatLog.Lexics.Action.Duration", 0);
+
+ // Initialize lexics cutter object
+ m_pLexics = new LexicsCutter(sAnalogsFileName, sInnormativeWordsFileName,
+ sConfig->GetBoolDefault("ChatLog.Lexics.Ignore.Spaces", true),
+ sConfig->GetBoolDefault("ChatLog.Lexics.Ignore.Repeats", true));
+
+ // Read additional parameters
+ m_bLexicsIgnoreGM = sConfig->GetBoolDefault("ChatLog.Lexics.Ignore.GM", true);
+ }
+ }
+
+ for (uint32 i = CHAT_LOG_CHAT; i < CHAT_LOG_COUNT; i++)
+ m_pLogs[i] = new ChatLogInfo(ChatLogType(i), m_bChatLogEnable, m_bLexicsEnable);
+
+ _OpenAllFiles();
+}
+
+void ChatLog::_OpenAllFiles()
+{
+ ACE_Guard guard(m_lock);
+ std::string sDate;
+ if (m_bChatLogDateSplit)
+ {
+ time_t t = time(NULL);
+ tm* aTm = localtime(&t);
+ char szDate[12];
+ sprintf(szDate, "%-4d-%02d-%02d", aTm->tm_year + 1900, aTm->tm_mon + 1, aTm->tm_mday);
+ sDate = szDate;
+
+ m_nLastDay = aTm->tm_mday;
+ }
+
+ if (m_bChatLogEnable)
+ {
+ for (uint32 i = CHAT_LOG_CHAT; i <= CHAT_LOG_COUNT - 1; ++i)
+ {
+ for (uint32 j = i - 1; j >= CHAT_LOG_CHAT; --j)
+ if (m_pLogs[i]->SetFileIfSame(m_pLogs[j]))
+ break;
+ m_pLogs[i]->OpenFile(m_bChatLogDateSplit, sDate, m_bChatLogUTFHeader);
+ }
+ }
+
+ // Initialize innormative log
+ if (m_bLexicsEnable && m_pInnormative)
+ m_pInnormative->OpenFile(m_bChatLogDateSplit, sDate, m_bChatLogUTFHeader);
+}
+
+void ChatLog::_CloseAllFiles()
+{
+ ACE_Guard guard(m_lock);
+ for (uint32 i = CHAT_LOG_CHAT; i <= CHAT_LOG_COUNT - 1; ++i)
+ {
+ if (m_pLogs[i]->GetFile())
+ {
+ for (uint32 j = i + 1; j <= CHAT_LOG_COUNT - 1; ++j)
+ m_pLogs[j]->CloseFileIfSame(m_pLogs[i]);
+ m_pLogs[i]->CloseFile();
+ }
+ }
+
+ if (m_pInnormative)
+ m_pInnormative->CloseFile();
+}
+
+void ChatLog::_CheckDateSwitch()
+{
+ if (m_bChatLogDateSplit)
+ {
+ time_t t = time(NULL);
+ tm* aTm = localtime(&t);
+ if (m_nLastDay != aTm->tm_mday)
+ {
+ // Open new files for new date
+ _CloseAllFiles();
+ _OpenAllFiles();
+ }
+ }
+}
+
+bool ChatLog::_ChatCommon(ChatLogType type, Player* player, std::string& msg)
+{
+ // Check message for innormative lexics and punish if necessary.
+ if (m_bLexicsEnable && m_pLexics && m_pLogs[type]->IsCut() && m_pLexics->CheckLexics(msg))
+ _Punish(player, msg);
+
+ if (!m_bChatLogEnable)
+ return false;
+
+ if (m_bChatLogIgnoreUnprintable)
+ {
+ // If should ignore unprintables, verify string by UTF8 here
+ unsigned int pos = 0;
+ std::string sChar;
+ while (LexicsCutter::ReadUTF8(msg, sChar, pos))
+ if (sChar.size() == 1)
+ if (sChar[0] < ' ')
+ return false ; // Unprintable detected
+ }
+
+ return true;
+}
+
+void ChatLog::_Punish(Player* player, std::string& msg)
+{
+ std::string logStr;
+
+ _AppendPlayerName(player, logStr);
+ _WriteLog(m_pInnormative, logStr, msg, msg);
+
+ // Check if should ignore GM
+ if (m_bLexicsIgnoreGM && (player->GetSession()->GetSecurity() > SEC_PLAYER))
+ return;
+
+ // Cut innormative lexics
+ if (m_bLexicsInnormativeCut)
+ msg = m_sLexicsCutReplacement;
+
+ if (!player || !player->GetSession())
+ return;
+
+ // special action
+ switch (m_LexicsAction)
+ {
+ case LEXICS_ACTION_SHEEP: _ApplySpell(player, 118); break;
+ case LEXICS_ACTION_STUN: _ApplySpell(player, 13005); break;
+ case LEXICS_ACTION_STUCK: _ApplySpell(player, 23312); break;
+ case LEXICS_ACTION_SICKNESS: _ApplySpell(player, 15007); break;
+ case LEXICS_ACTION_SHEAR: _ApplySpell(player, 41032); break;
+ case LEXICS_ACTION_DIE:
+ player->DealDamage(player, player->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ break;
+ case LEXICS_ACTION_DRAIN:
+ player->DealDamage(player, player->GetHealth() - 5, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ break;
+ case LEXICS_ACTION_SILENCE:
+ player->GetSession()->m_muteTime = time(NULL) + int64(m_unLexicsActionDuration / 1000);
+ break;
+ default:
+ // No action except logging
+ break;
+ }
+}
+
+inline void ChatLog::_ApplySpell(Player *pPlayer, uint32 spellId)
+{
+ if (Aura *a = pPlayer->AddAura(spellId, pPlayer))
+ a->SetDuration(m_unLexicsActionDuration);
+}
+
+inline void ChatLog::_WriteLog(ChatLogInfo* pLog, std::string& logStr, const std::string& msg, const std::string& origMsg)
+{
+ if (!pLog)
+ return;
+
+ if (pLog->IsScreen())
+ printf("%s %s", logStr.c_str(), msg.c_str());
+
+ _CheckDateSwitch();
+ logStr.append(" ").append(origMsg);
+ pLog->WriteFile(logStr);
+}
+
+inline void ChatLog::_AppendPlayerName(Player* player, std::string& s)
+{
+ s.append("[").append(player ? player->GetName() : "???").append("]");
+}
+
+inline void ChatLog::_AppendGroupMembers(Group* group, std::string& s)
+{
+ if (!group)
+ s.append(" {unknown group}:");
+ else
+ {
+ char sz[32];
+ sprintf(sz, UI64FMTD, group->GetGUID());
+ s.append(" {").append(sz).append("} [");
+ uint64 leaderGUID = group->GetLeaderGUID();
+ if (Player* pLeader = sObjectMgr->GetPlayer(leaderGUID))
+ s.append(pLeader->GetName());
+
+ Group::MemberSlotList members = group->GetMemberSlots();
+ for (Group::member_citerator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if (itr->guid == leaderGUID)
+ continue;
+
+ if (Player* pMember = sObjectMgr->GetPlayer(itr->guid))
+ s.append(",").append(pMember->GetName());
+ }
+ s.append("]:");
+ }
+}
+
+void ChatLog::OnChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg)
+{
+ std::string origMsg(msg);
+ if (!_ChatCommon(CHAT_LOG_CHAT, player, msg))
+ return;
+
+ std::string logStr;
+ switch (type)
+ {
+ case CHAT_MSG_SAY: logStr.append("{SAY}"); break;
+ case CHAT_MSG_EMOTE: logStr.append("{EMOTE}"); break;
+ case CHAT_MSG_YELL: logStr.append("{YELL}"); break;
+ }
+ _AppendPlayerName(player, logStr);
+ _WriteLog(m_pLogs[CHAT_LOG_CHAT], logStr, msg, origMsg);
+}
+
+void ChatLog::OnChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Player* receiver)
+{
+ std::string origMsg(msg);
+ if (!_ChatCommon(CHAT_LOG_WHISPER, player, msg))
+ return;
+
+ std::string logStr;
+ _AppendPlayerName(player, logStr);
+ logStr.append("->");
+ _AppendPlayerName(receiver, logStr);
+
+ _WriteLog(m_pLogs[CHAT_LOG_WHISPER], logStr, msg, origMsg);
+}
+
+void ChatLog::OnChat(Player* player, uint32 type, uint32 /*lang*/, std::string& msg, Group* group)
+{
+ std::string origMsg(msg);
+ std::string logStr;
+ _AppendPlayerName(player, logStr);
+
+ switch (type)
+ {
+ case CHAT_MSG_PARTY:
+ case CHAT_MSG_PARTY_LEADER:
+ if (_ChatCommon(CHAT_LOG_PARTY, player, msg))
+ {
+ switch (type)
+ {
+ case CHAT_MSG_PARTY: logStr.append("->PARTY"); break;
+ case CHAT_MSG_PARTY_LEADER: logStr.append("->PARTY_LEADER"); break;
+ }
+ _AppendGroupMembers(group, logStr);
+ _WriteLog(m_pLogs[CHAT_LOG_PARTY], logStr, msg, origMsg);
+ }
+ break;
+ case CHAT_MSG_RAID_LEADER:
+ case CHAT_MSG_RAID_WARNING:
+ case CHAT_MSG_RAID:
+ if (_ChatCommon(CHAT_LOG_RAID, player, msg))
+ {
+ switch (type)
+ {
+ case CHAT_MSG_RAID_LEADER: logStr.append("->RAID_LEADER");
+ case CHAT_MSG_RAID_WARNING: logStr.append("->RAID_WARN");
+ case CHAT_MSG_RAID: logStr.append("->RAID");
+ }
+ _AppendGroupMembers(group, logStr);
+ _WriteLog(m_pLogs[CHAT_LOG_RAID], logStr, msg, origMsg);
+ }
+ break;
+ case CHAT_MSG_BATTLEGROUND:
+ case CHAT_MSG_BATTLEGROUND_LEADER:
+ if (_ChatCommon(CHAT_LOG_BATTLEGROUND, player, msg))
+ {
+ switch (type)
+ {
+ case CHAT_MSG_BATTLEGROUND: logStr.append("->BG"); break;
+ case CHAT_MSG_BATTLEGROUND_LEADER: logStr.append("->BG_LEADER"); break;
+ }
+ _AppendGroupMembers(group, logStr);
+ _WriteLog(m_pLogs[CHAT_LOG_BATTLEGROUND], logStr, msg, origMsg);
+ }
+ break;
+ }
+}
+
+void ChatLog::OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild)
+{
+ std::string origMsg(msg);
+ if (!_ChatCommon(CHAT_LOG_GUILD, player, msg))
+ return;
+
+ std::string logStr;
+ _AppendPlayerName(player, logStr);
+ switch (type)
+ {
+ case CHAT_MSG_GUILD: logStr.append("->GUILD"); break;
+ case CHAT_MSG_OFFICER: logStr.append("->GUILD_OFF"); break;
+ }
+ logStr.append(" {").append(guild ? guild->GetName() : "unknowng guild").append("}:");
+
+ _WriteLog(m_pLogs[CHAT_LOG_GUILD], logStr, msg, origMsg);
+}
+
+void ChatLog::OnChat(Player *player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Channel* channel)
+{
+ std::string origMsg(msg);
+ if (!_ChatCommon(CHAT_LOG_CHANNEL, player, msg))
+ return;
+
+ std::string logStr;
+ _AppendPlayerName(player, logStr);
+ logStr.append(" {").append(channel ? channel->GetName() : "Unknown channel").append("}");
+
+ _WriteLog(m_pLogs[CHAT_LOG_CHANNEL], logStr, msg, origMsg);
+}
+
+void AddSC_lexics_chat_log()
+{
+ new ChatLog();
+}
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/scripts/World/ChatLog/ChatLog.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/scripts/World/ChatLog/ChatLog.h Wed Apr 27 02:46:43 2011 +0400
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS
+ *
+ * Copyright (C) 2008-2014 Trinity
+ *
+ * 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 TRINITYCORE_CHATLOG_H
+#define TRINITYCORE_CHATLOG_H
+
+#include "ScriptPCH.h"
+#include "ChatLexicsCutter.h"
+
+enum ChatLogType
+{
+ CHAT_LOG_NONE,
+ CHAT_LOG_CHAT,
+ CHAT_LOG_PARTY,
+ CHAT_LOG_GUILD,
+ CHAT_LOG_WHISPER,
+ CHAT_LOG_CHANNEL,
+ CHAT_LOG_RAID,
+ CHAT_LOG_BATTLEGROUND,
+
+ CHAT_LOG_COUNT,
+ CHAT_LOG_INNORMATIVE
+};
+
+enum LexicsActions
+{
+ LEXICS_ACTION_LOG,
+ LEXICS_ACTION_SHEEP,
+ LEXICS_ACTION_STUN,
+ LEXICS_ACTION_DIE,
+ LEXICS_ACTION_DRAIN,
+ LEXICS_ACTION_SILENCE,
+ LEXICS_ACTION_STUCK,
+ LEXICS_ACTION_SICKNESS,
+ LEXICS_ACTION_SHEAR,
+};
+
+class ChatLogInfo
+{
+private:
+ FILE *m_file;
+ std::string m_name;
+ bool m_screenFlag;
+ bool m_cutFlag;
+ ChatLogType m_type;
+ ACE_Thread_Mutex m_lock;
+
+public:
+ ChatLogInfo(ChatLogType type, bool bChat, bool bLexics);
+
+ void OpenFile(bool bDateSplit, const std::string& sDate, bool bUTFHeader);
+ void CloseFile()
+ {
+ ACE_Guard guard(m_lock);
+ if (m_file)
+ {
+ fclose(m_file);
+ m_file = NULL;
+ }
+ }
+ void WriteFile(const std::string& msg);
+
+ FILE* GetFile() const { return m_file; }
+ std::string GetName() const { return m_name; }
+ bool IsCut() const { return m_cutFlag; }
+ bool IsScreen() const { return m_screenFlag; }
+
+ bool SetFileIfSame(ChatLogInfo* pLog)
+ {
+ if (m_name == pLog->GetName())
+ {
+ m_file = pLog->GetFile();
+ return true;
+ }
+ return false;
+ }
+ void CloseFileIfSame(ChatLogInfo* pLog)
+ {
+ if (m_file == pLog->GetFile())
+ m_file = NULL;
+ }
+};
+
+class ChatLog : public PlayerScript
+{
+public:
+ static std::string GetChatNameByType(ChatLogType type);
+ static std::string GetChatDescByType(ChatLogType type);
+ static void OutTimestamp(FILE *file);
+
+ ChatLog();
+ ~ChatLog();
+
+ void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg);
+ void OnChat(Player *player, uint32 type, uint32 lang, std::string& msg, Player *receiver);
+ void OnChat(Player *player, uint32 type, uint32 lang, std::string& msg, Group *group);
+ void OnChat(Player *player, uint32 type, uint32 lang, std::string& msg, Guild *guild);
+ void OnChat(Player *player, uint32 type, uint32 lang, std::string& msg, Channel *channel);
+
+private:
+ bool _ChatCommon(ChatLogType type, Player *player, std::string &msg);
+ void _Punish(Player* player, std::string& msg);
+ void _ApplySpell(Player *player, uint32 spellId);
+
+ void _Initialize();
+ void _OpenAllFiles();
+ void _CloseAllFiles();
+ void _CheckDateSwitch();
+ void _AppendPlayerName(Player* player, std::string& s);
+ void _AppendGroupMembers(Group* group, std::string& s);
+ void _WriteLog(ChatLogInfo* pLog, std::string& logStr, const std::string& msg, const std::string& origMsg);
+
+ // Chats
+ bool m_bChatLogEnable;
+ bool m_bChatLogDateSplit;
+ bool m_bChatLogUTFHeader;
+ bool m_bChatLogIgnoreUnprintable;
+
+ int32 m_nLastDay;
+
+ ChatLogInfo* m_pLogs[CHAT_LOG_COUNT];
+
+ // Lexics
+ LexicsCutter* m_pLexics;
+
+ bool m_bLexicsEnable;
+ bool m_bLexicsInnormativeCut;
+ bool m_bLexicsIgnoreGM;
+
+ std::string m_sLexicsCutReplacement;
+ LexicsActions m_LexicsAction;
+ uint32 m_unLexicsActionDuration;
+
+ ChatLogInfo* m_pInnormative;
+ ACE_Thread_Mutex m_lock;
+};
+
+#define sChatLog (*ACE_Singleton::instance())
+#endif
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/worldserver/CMakeLists.txt
--- a/src/server/worldserver/CMakeLists.txt Wed Apr 27 02:04:17 2011 +0400
+++ b/src/server/worldserver/CMakeLists.txt Wed Apr 27 02:46:43 2011 +0400
@@ -180,15 +180,21 @@
add_custom_command(TARGET worldserver
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/innormative_words.txt.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/letter_analogs.txt.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
endif()
if( UNIX )
install(TARGETS worldserver DESTINATION bin)
install(FILES worldserver.conf.dist DESTINATION etc)
+ install(FILES innormative_words.txt.dist DESTINATION bin)
+ install(FILES letter_analogs.txt.dist DESTINATION bin)
elseif( WIN32 )
install(TARGETS worldserver DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES worldserver.conf.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
+ install(FILES innormative_words.txt.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
+ install(FILES letter_analogs.txt.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()
# Generate precompiled header
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/worldserver/innormative_words.txt.dist
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/worldserver/innormative_words.txt.dist Wed Apr 27 02:46:43 2011 +0400
@@ -0,0 +1,1 @@
+
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/worldserver/letter_analogs.txt.dist
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/worldserver/letter_analogs.txt.dist Wed Apr 27 02:46:43 2011 +0400
@@ -0,0 +1,59 @@
+?пїЅ??aA
+?пїЅ?пїЅbB6
+???пїЅvVwWB
+???пїЅgGr
+???пїЅdDg
+?пїЅ?пїЅ?пїЅ??eE3
+?пїЅ???пїЅ?пїЅeE3
+?пїЅ?пїЅzZ
+?пїЅ?пїЅzZ3
+???????пїЅiIuU1
+???пїЅ????iIjJuU1
+????kK
+?пїЅ?пїЅlL1
+????mM
+????nNhH
+????oO0Q
+????pPn
+???пїЅrRpP
+????cC
+?пїЅ??tT7
+????uUyY
+?пїЅ?пїЅfF
+?пїЅ??hHxX
+?пїЅ?пїЅcC
+?пїЅ?пїЅ4
+?пїЅ??
+?пїЅ?пїЅ
+????b
+?пїЅ?пїЅyY
+???пїЅb
+???пїЅ3
+???пїЅuU
+????R
+aA?пїЅ??
+bB?пїЅ?пїЅ?пїЅ
+cC?????пїЅ?пїЅ
+dD???пїЅ
+eE?пїЅ?пїЅ3
+fF?пїЅ?пїЅ
+gG???пїЅ
+hH?пїЅ??????
+iI???????пїЅ1
+jJ???пїЅ????1
+kK????
+lL?пїЅ?пїЅ1
+mM????
+nN??????
+oO????0
+p????P???пїЅ
+qQ??0
+rR???пїЅ??????
+sS????
+tT?пїЅ??
+uU????????
+vV???пїЅ
+wW???пїЅ
+xX?пїЅ??
+yY?пїЅ?пїЅ????
+zZ?пїЅ?пїЅ
diff -r ce99f0ba5b0f -r d4cdfd0078dd src/server/worldserver/worldserver.conf.dist
--- a/src/server/worldserver/worldserver.conf.dist Wed Apr 27 02:04:17 2011 +0400
+++ b/src/server/worldserver/worldserver.conf.dist Wed Apr 27 02:46:43 2011 +0400
@@ -689,7 +689,6 @@
LogDB.Chat = 0
-
# ChatLogFile
# Description: Log file for chat logs.
# Default: "Chat.log" - (Enabled)
@@ -782,6 +781,194 @@
#
###################################################################################################
+###############################################################################
+# CHAT LOGGING AND LEXICS CUTTER
+#
+# ChatLog.Enable
+# Enable system of chat logging.
+# Default: 1 - on
+# 0 - off
+#
+
+ChatLog.Enable = 1
+
+#
+# ChatLog.DateSplit
+# Split log files by date (filename must include $d as date placeholder).
+# Default: 1 - split
+# 0 - do not split
+#
+
+ChatLog.DateSplit = 1
+
+#
+# ChatLog.UTFHeader
+# Add UTF8 header at the beginning of new file.
+# Default: 1 - add
+# 0 - do not add
+#
+
+ChatLog.UTFHeader = 1
+
+#
+# ChatLog.Ignore.Unprintable
+# Ignore messages with unprintable characters.
+# Default: 1 - ignore
+# 0 - do not ignore
+#
+
+ChatLog.Ignore.Unprintable = 1
+
+#
+# ChatLog.Lexics.Enable
+# Enable lexics cutter in chats.
+# Default: 1 - on
+# 0 - off
+#
+
+ChatLog.Lexics.Enable = 1
+
+#
+# ChatLog.Lexics.Cut.Enable
+# Cut innormative lexics in chat.
+# Default: 1 - cut
+# 0 - do not cut
+#
+
+ChatLog.Lexics.Cut.Enable = 1
+
+#
+# ChatLog.Lexics.Cut.Replacement
+# Text shown instead of message with innormative lexics.
+#
+
+ChatLog.Lexics.Cut.Replacement = &!@^%!^&*!!!
+
+#
+# ChatLog.Lexics.WordsFile
+# Path to the file with words considered as innormative.
+#
+
+ChatLog.Lexics.WordsFile = innormative_words.txt
+
+#
+# ChatLog.Lexics.AnalogsFile
+# Path to the file with letter analogs.
+#
+
+ChatLog.Lexics.AnalogsFile = letter_analogs.txt
+
+#
+# ChatLog.Lexics.Ignore.Spaces
+# Ignore spaces in filtered words. Example: W O R D
+# Default: 1 - ignore
+# 0 - do not ignore
+#
+
+ChatLog.Lexics.Ignore.Spaces = 1
+
+#
+# ChatLog.Lexics.Ignore.Repeats
+# Ignore repeating symbols in filtered words. Example: WWWOOOORRRRRRDDD
+# Default: 1 - ignore
+# 0 - do not ignore
+#
+
+ChatLog.Lexics.Ignore.Repeats = 1
+
+#
+# ChatLog.Lexics.Ignore.GM
+# Ignore (do not filter) messages from GM.
+# Default: 1 - ignore
+# 0 - do not ignore
+#
+
+ChatLog.Lexics.Ignore.GM = 1
+
+#
+# ChatLog.Lexics.Action
+# Action taken when bad lexics is found.
+# Default: 0 - log only
+# 1 - polymorph
+# 2 - stun
+# 3 - instant kill
+# 4 - leave 5 health
+# 5 - mute
+# 6 - stuck (works as stun + 50% health) [by KAPATEJIb]
+# 7 - resurrection sickness [by Koshei]
+# 8 - shear [by Koshei]
+#
+
+ChatLog.Lexics.Action = 0
+
+#
+# ChatLog.Lexics.Action.Duration
+# Duration of action in milliseconds.
+# Default: 0 - no duration
+#
+
+ChatLog.Lexics.Action.Duration = 0
+
+#
+# SETTINGS FOR DIFFERENT CHAT TYPES
+# Available types:
+# * Chat - common chat
+# * Party - party chat
+# * Guild - guild chat
+# * Whisper - whispers
+# * Channel - channels
+# * Raid - raid chat
+# * BattleGround - battleground chat
+# * Lexics.Innormative - messages filtered by lexics cutter
+#
+# ChatLog.*.File
+# Log file name for given chat type.
+#
+# ChatLog.*.Screen
+# Output message in server console for given chat type.
+# Default: 0 - do not show
+# 1 - show
+#
+# ChatLog.Lexics.*.Cut
+# Cut lexics for given chat type (except Innormative).
+# Default: 1 - cut
+# 0 - do not cut
+#
+
+ChatLog.Chat.File = "main_chat-$d.log"
+ChatLog.Chat.Screen = 0
+ChatLog.Lexics.Chat.Cut = 1
+
+ChatLog.Party.File = "party_chat-$d.log"
+ChatLog.Party.Screen = 0
+ChatLog.Lexics.Party.Cut = 1
+
+ChatLog.Guild.File = "guild_chat-$d.log"
+ChatLog.Guild.Screen = 0
+ChatLog.Lexics.Guild.Cut = 1
+
+ChatLog.Whisper.File = "whisper_chat-$d.log"
+ChatLog.Whisper.Screen = 0
+ChatLog.Lexics.Whisper.Cut = 1
+
+ChatLog.Channel.File = "channel_chat-$d.log"
+ChatLog.Channel.Screen = 0
+ChatLog.Lexics.Channel.Cut = 1
+
+ChatLog.Raid.File = "raid_chat-$d.log"
+ChatLog.Raid.Screen = 0
+ChatLog.Lexics.Raid.Cut = 1
+
+ChatLog.BattleGround.File = "bg_chat-$d.log"
+ChatLog.BattleGround.Screen = 0
+ChatLog.Lexics.BattleGround.Cut = 1
+
+ChatLog.Lexics.Innormative.File = "innormative-$d.log"
+ChatLog.Lexics.Innormative.Screen = 0
+
+#
+###############################################################################
+
###################################################################################################
# SERVER SETTINGS
#